home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 May / EnigmA AMIGA RUN 18 (1997)(G.R. Edizioni)(IT)[!][issue 1997-05][EAR-CD II].iso / ghost / gs403src_amiga.lha / gs4.03 / gdevamiga.c < prev    next >
C/C++ Source or Header  |  1997-04-02  |  115KB  |  5,269 lines

  1. /* Copyright (C) 1992, 1995 Aladdin Enterprises.  All rights reserved.
  2.  
  3.   This file is part of Aladdin Ghostscript.
  4.  
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.  
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevamiga.c */
  20. /* Amiga driver for Ghostscript library, requires Kickstart 2.04 or higher */
  21.  
  22. /* Original development and maintenance up to and including gs3.5.3:
  23.  *
  24.  *    Olaf 'Olsen' Barthel
  25.  *
  26.  *    Address:    Olaf Barthel
  27.  *                Brabeckstrasse 35
  28.  *                D-30559 Hannover
  29.  *    Internet:    olsen@sourcery.han.de
  30.  *
  31.  *
  32.  * Current maintenance, libnix integration and 'autoconfiscation':
  33.  *
  34.  *    Joop van de Wege
  35.  *
  36.  *    Internet:    JoopvandeWege@mail.mococo.nl
  37.  *
  38.  *
  39.  * Revised device/size/resolution handling:
  40.  *
  41.  *    Steffen Opel
  42.  *
  43.  *    Internet:   opel@rumms.uni-mannheim.de
  44.  */
  45.  
  46. #include <clib/macros.h>
  47. #include <datatypes/pictureclass.h>
  48. #include <dos/dostags.h>
  49. #include <dos/rdargs.h>
  50. #include <dos/var.h>
  51. #include <dos/dos.h>
  52. #include <devices/printer.h>
  53. #include <devices/prtbase.h>
  54. #include <devices/prtgfx.h>
  55. #include <exec/errors.h>
  56. #include <exec/memory.h>
  57. #include <graphics/displayinfo.h>
  58. #include <graphics/gfxbase.h>
  59. #include <intuition/intuitionbase.h>
  60. #include <intuition/gadgetclass.h>
  61. #include <intuition/imageclass.h>
  62. #include <intuition/icclass.h>
  63. #include <libraries/asl.h>
  64. #include <libraries/iffparse.h>
  65.  
  66. #include <proto/asl.h>
  67. #include <proto/dos.h>
  68. #include <proto/exec.h>
  69. #define BltBitMap BlitBitMap    /* Hide weird compiler error! */
  70. #include <proto/graphics.h>
  71. #undef BltBitMap
  72. #include <proto/iffparse.h>
  73. #include <proto/intuition.h>
  74. #include <proto/layers.h>
  75. #include <proto/utility.h>
  76.  
  77. #include "gscdefs.h"
  78. #include "gserrors.h"
  79. #include "gx.h"        /* for gx_bitmap; includes std.h */
  80. #include "gxdevice.h"
  81. #include "gxfixed.h"    /* needed for amiga_put_params only */
  82. #include "gsparam.h"
  83.  
  84. #include <string.h>
  85. #include <signal.h>
  86.  
  87.     /* Magic value to compute the resolution from the display database.
  88.      *
  89.      * To compute the dots_per_inch resolution from the ticks_per_pixel 
  90.      * resolution in the display database the common base is needed. 
  91.      * These base ensures that all Display Modes will be displayed with 
  92.      * the same absolute aspect ratio. Don't ask me how the ticks_per_pixel 
  93.      * entries are computed exactly, the supplied value has been determined 
  94.      * with respect to GfxBase->NormalDisplay[Rows|Columns], some monitors
  95.      * and a meter. Therefore it may be fine tuned to fit any specific 
  96.      * monitor/gfx-board environment.
  97.      *
  98.      * TODO: Resolve the constitutional calculation for those entries
  99.      * in the display database!
  100.      */
  101.  
  102. #define MAGIC_DPI_BASE_VALUE    1447
  103.  
  104.     /* Initial values for resolution and size. */
  105.  
  106. #define INITIAL_X_DPI        72
  107. #define INITIAL_Y_DPI        72
  108.  
  109. #ifdef A4
  110. /* A4 paper (210mm x 297mm).  The dimensions are off by a few nm.... */
  111. #define INITIAL_WIDTH        (int)(8.27 * INITIAL_X_DPI)
  112. #define INITIAL_HEIGHT        (int)(11.7 * INITIAL_Y_DPI)
  113. #else
  114. /* U.S. letter paper (8.5" x 11"). */
  115. #define INITIAL_WIDTH        (int)(8.5 * INITIAL_X_DPI)
  116. #define INITIAL_HEIGHT        (int)(11.0 * INITIAL_Y_DPI)
  117. #endif
  118.  
  119.     /* Default Display Mode. */
  120.  
  121. #define DEFAULT_DISPLAYMODE    ""
  122.  
  123.     /* Default output file name. */
  124.  
  125. #define DEFAULT_FILENAME    "gs_page"
  126.  
  127.     /* Turn a byte into a 24 bit colour value. */
  128.  
  129. #define SPREAD(i)    ((ULONG)(i) << 24 | (ULONG)(i) << 16 | (ULONG)(i) << 8 | (i))
  130.  
  131.     /* Scroller gadget IDs. */
  132.  
  133. enum    {    VERTICAL_SCROLLER,    HORIZONTAL_SCROLLER,
  134.         UP_ARROW,        DOWN_ARROW,
  135.         LEFT_ARROW,        RIGHT_ARROW,
  136.  
  137.         GADGET_COUNT
  138.     };
  139.  
  140.     /* Scroller arrow IDs. */
  141.  
  142. enum    {    UP_IMAGE,        DOWN_IMAGE,
  143.         LEFT_IMAGE,        RIGHT_IMAGE,
  144.  
  145.         IMAGE_COUNT
  146.     };
  147.  
  148.     /* Codes for the MoveAround() routine. */
  149.  
  150. enum    {    MOVE_MIN,MOVE_FAR_DOWN,MOVE_DOWN,MOVE_UP,MOVE_FAR_UP,MOVE_MAX };
  151.  
  152.     /* Some handy bit masks. */
  153.  
  154. #define SIG_KILL    SIGBREAKF_CTRL_C
  155. #define SIG_HANDSHAKE    SIGF_SINGLE
  156. #define SIG_WAKEUP    SIGBREAKF_CTRL_E
  157.  
  158.     /* Static dimensions of scroller arrows. */
  159.  
  160. #define ARROW_WIDTH    16
  161. #define ARROW_HEIGHT    11
  162.  
  163.     /* The `Help' key raw code. */
  164.  
  165. #define HELP_CODE    95
  166.  
  167.     /* Minimum window inner area dimension. */
  168.  
  169. #define MINIMUM_WIDTH    64
  170. #define MINIMUM_HEIGHT    32
  171.  
  172.     /* Handy superbitmap window macros. */
  173.  
  174. #define LAYERXOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_X)
  175. #define LAYERYOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_Y)
  176.  
  177.     /* User input to listen to. */
  178.  
  179. #define IDCMP_FLAGS    (IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE | IDCMP_NEWSIZE | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_RAWKEY)
  180.  
  181.     /* Chunk IDs. */
  182.  
  183. #define ID_ANNO        MAKE_ID('A','N','N','O')
  184. #define ID_DPI        MAKE_ID('D','P','I',' ')
  185.  
  186. typedef struct
  187. {
  188.     UWORD        dpi_x;
  189.     UWORD        dpi_y;
  190. } DPIHeader;
  191.  
  192.     /* Packer modes. */
  193.  
  194. #define DUMP        0
  195. #define RUN        1
  196.  
  197.     /* Minimum data run size, maximum data run size and maximum cache size. */
  198.  
  199. #define MINRUN        3
  200. #define MAXRUN        128
  201. #define MAXDAT        128
  202.  
  203.     /* This module actually implements four different Amiga based
  204.      * devices. As the rendering operations are all the same,
  205.      * one single device definition is sufficient.
  206.      */
  207.  
  208. typedef struct gx_device_amiga
  209. {
  210.     gx_device_common;
  211.  
  212.     struct Screen    *screen;    /* Any screen */
  213.     struct Window    *window;    /* Some window to be opened on the Workbench screen */
  214.  
  215.     struct BitMap    *super_bitmap;    /* Window superbitmap area */
  216.     struct Gadget    **gadget;    /* Scroller gadgets */
  217.     struct Image    **image;    /* Scroller arrow images */
  218.  
  219.     struct Task    *dispatcher;    /* Slider dispatch task */
  220.     struct Process    *main;        /* Main program */
  221.  
  222.     struct RastPort    *rport;        /* Rendering area */
  223.  
  224.     struct IODRPReq *printer;    /* Printer interface data */
  225.     struct MsgPort    *port;        /* Printer io data */
  226.  
  227.     struct ColorMap    *colormap;    /* A black/white colour map */
  228.     struct BitMap    *bitmap;    /* Rendering bitmap data */
  229.     PLANEPTR     bitplane;    /* Rendering raster */
  230.  
  231.     gx_color_index     last_pen;    /* The last colour set */
  232.  
  233.     char        display_mode[DISPLAYNAMELEN + 1];    /* The Display Mode */
  234.     char        file_name[256];/* The output file name */
  235.     int         page_count;    /* The page number counter */
  236.  
  237.     int         cube_size;    /* Colour cube size, 0 for b/w */
  238.     struct RastPort    *temp_rport;    /* Temporary raster port for pixmap imaging. */
  239.     UBYTE        *temp_array;    /* Temporary colour manipulation array. */
  240.     LONG        *pens;
  241. } gx_device_amiga;
  242.  
  243.     /* Cheap, but effective macro for casting the device argument ;-) */
  244.  
  245. #define xdev ((gx_device_amiga *)dev)
  246.  
  247.     /* Support functions */
  248.  
  249. private int amiga_open(gx_device *dev, ULONG Mode);
  250. private VOID set_mono_device(gx_device_amiga *dev);
  251. private VOID set_colour_device(gx_device_amiga *dev, int cube_size, 
  252.     LONG *pens);
  253. private VOID set_colour_printer_device(gx_device_amiga *dev, LONG CubeSize);
  254. private LONG * AllocatePens(struct ViewPort *VPort, LONG CubeSize);
  255. private VOID DeleteBitMap(struct BitMap *BitMap, BOOL Private);
  256. private struct BitMap * CreateBitMap(LONG Width, LONG Height, LONG Depth, 
  257.     ULONG Flags, struct BitMap *Friend, BOOL Private);
  258. private VOID DeleteTempRPort(struct RastPort *Temp);
  259. private struct RastPort * CreateTempRPort(struct RastPort *Source);
  260. private LONG Euclid(LONG a, LONG b);
  261. private BYTE * PutDump(register BYTE *Destination, register LONG Count);
  262. private BYTE * PutRun(register BYTE *Destination, LONG Count, WORD Char);
  263. private LONG PackRow(PLANEPTR *SourcePtr, register BYTE *Destination, 
  264.     LONG RowSize);
  265. private BOOL PutBODY(struct IFFHandle *Handle, struct BitMap *BitMap);
  266. private BOOL PutANNO(struct IFFHandle *Handle);
  267. private BOOL PutCAMG(struct IFFHandle *Handle);
  268. private BOOL PutCMAP(struct IFFHandle *Handle);
  269. private BOOL PutDPI(struct IFFHandle *Handle, UWORD X_DPI, UWORD Y_DPI);
  270. private BOOL PutBMHD(struct IFFHandle *Handle, LONG Width, LONG Height, 
  271.     UWORD X_DPI, UWORD Y_DPI);
  272. private BOOL SaveBitMap(STRPTR Name, struct BitMap *BitMap, LONG Width, 
  273.     LONG Height, UWORD X_DPI, UWORD Y_DPI);
  274. private VOID DispatchTask(VOID);
  275. private VOID DeleteScrollers(gx_device *dev);
  276. private BOOL CreateScrollers(gx_device *dev, struct Screen *Screen);
  277. private VOID WindowResize(gx_device *dev);
  278. private VOID WindowUpdate(struct Gadget *Gadget, gx_device *dev);
  279. private VOID MoveAround(struct Gadget *Gadget, LONG How, gx_device *dev);
  280. private VOID DispatchSuperWindow(gx_device *dev);
  281. private VOID PrintPrinterError(const char *header, LONG io_Error);
  282. void devcleanup(VOID);
  283.  
  284.     /* Device procedures (see gxdevice.h for the definitions) */
  285.  
  286. private dev_proc_open_device(amiga_open_default);
  287. private dev_proc_open_device(amiga_open_custom);
  288. private dev_proc_open_device(amiga_open_printer);
  289. private dev_proc_open_device(amiga_open_ilbm);
  290. private dev_proc_output_page(amiga_output_page);
  291. private dev_proc_output_page(amiga_output_page_printer);
  292. private dev_proc_output_page(amiga_output_page_ilbm);
  293. private dev_proc_close_device(amiga_close);
  294. private dev_proc_close_device(amiga_close_printer);
  295. private dev_proc_close_device(amiga_close_ilbm);
  296. private dev_proc_map_rgb_color(amiga_map_rgb_color);
  297. private dev_proc_map_rgb_color(amiga_color_map_rgb_color);
  298. private dev_proc_map_rgb_color(amiga_color_map_rgb_color_pen);
  299. private dev_proc_map_color_rgb(amiga_map_color_rgb);
  300. private dev_proc_map_color_rgb(amiga_color_map_color_rgb);
  301. private dev_proc_map_color_rgb(amiga_color_map_color_rgb_pen);
  302. private dev_proc_fill_rectangle(amiga_fill_rectangle);
  303. private dev_proc_fill_rectangle(amiga_fill_rectangle_raw);
  304. private dev_proc_fill_rectangle(amiga_fill_rectangle_raw_color);
  305. private dev_proc_copy_mono(amiga_copy_mono);
  306. private dev_proc_copy_mono(amiga_copy_mono_raw);
  307. private dev_proc_copy_mono(amiga_copy_mono_raw_color);
  308. private dev_proc_copy_color(amiga_copy_color);
  309. private dev_proc_copy_color(amiga_copy_color_raw);
  310. private dev_proc_copy_color(amiga_copy_color8);
  311. private dev_proc_copy_color(amiga_copy_color_raw_color16);
  312. private dev_proc_draw_line(amiga_draw_line);
  313. private dev_proc_draw_line(amiga_draw_line_raw);
  314. private dev_proc_draw_line(amiga_draw_line_raw_color);
  315. private dev_proc_get_bits(amiga_get_bits);
  316. private dev_proc_get_params(amiga_get_params);
  317. private dev_proc_put_params(amiga_put_params);
  318.  
  319.     /* External reference to some libraries, required for version checking, etc. */
  320.  
  321. extern struct GfxBase *GfxBase;
  322. extern struct Library *AslBase;
  323.  
  324.     /* Detect wether user has set -g and/or -r at the command line */
  325.  
  326. private BOOL ResolutionSwitch = FALSE;
  327. private BOOL GeometrySwitch = FALSE;
  328.  
  329.     /* Number of packed bytes and pack buffer. */
  330.  
  331. private LONG PackedBytes;
  332. private BYTE Buffer[MAXDAT + 1];
  333.  
  334.     /* Bit masks. */
  335.  
  336. private UBYTE shift[8] = { 128, 64, 32, 16,  8,  4,  2,  1 };
  337. private UBYTE masks[8] = { 127,191,223,239,247,251,253,254 };
  338.  
  339.     /* Dark (black) and light (white) rendering colours; the default device
  340.      * determines the actual colours to be used by looking into the screen
  341.      * colour lookup table, the other device drivers leave these values
  342.      * untouched.
  343.      */
  344.  
  345. private UBYTE DarkPen = 0;
  346. private UBYTE LightPen = 1;
  347.  
  348.     /* Device routine jump tables */
  349.  
  350. private gx_device_procs amiga_default_procs =
  351. {
  352.     amiga_open_default,
  353.     NULL,            /* get_initial_matrix */
  354.     NULL,            /* sync_output */
  355.     amiga_output_page,
  356.     amiga_close,
  357.     amiga_map_rgb_color,
  358.     amiga_map_color_rgb,
  359.     amiga_fill_rectangle,
  360.     NULL,            /* tile_rectangle */
  361.     amiga_copy_mono,
  362.     amiga_copy_color,
  363.     amiga_draw_line,
  364.     NULL,            /* get_bits */
  365.     amiga_get_params,
  366.     amiga_put_params,
  367.     NULL,            /* map_cmyk_color */
  368.     NULL,            /* get_xfont_procs */
  369.     NULL,            /* get_xfont_device */
  370.     NULL,            /* map_rgb_alpha_color */
  371.     gx_page_device_get_page_device,            /* get_page_device */
  372.     NULL,            /* get_alpha_bits */
  373.     NULL,            /* copy_alpha */
  374.     NULL,            /* get_band */
  375.     NULL,            /* copy_rop */
  376.     NULL,            /* fill_path */
  377.     NULL,            /* stroke_path */
  378.     NULL,            /* fill_mask */
  379.     NULL,            /* fill_trapezoid */
  380.     NULL,            /* fill_parallelogram */
  381.     NULL,            /* fill_triangle */
  382.     NULL,            /* draw_thin_line */
  383.     NULL,            /* begin_image */
  384.     NULL,            /* image_data */
  385.     NULL,            /* end_image */
  386.     NULL,            /* strip_tile_rectangle */
  387.     NULL,            /* strip_copy_rop */
  388. };
  389.  
  390. private gx_device_procs amiga_custom_procs =
  391. {
  392.     amiga_open_custom,
  393.     NULL,            /* get_initial_matrix */
  394.     NULL,            /* sync_output */
  395.     amiga_output_page,
  396.     amiga_close,
  397.     amiga_map_rgb_color,
  398.     amiga_map_color_rgb,
  399.     amiga_fill_rectangle,
  400.     NULL,            /* tile_rectangle */
  401.     amiga_copy_mono,
  402.     amiga_copy_color,
  403.     amiga_draw_line,
  404.     NULL,            /* get_bits */
  405.     amiga_get_params,
  406.     amiga_put_params,
  407.     NULL,            /* map_cmyk_color */
  408.     NULL,            /* get_xfont_procs */
  409.     NULL,            /* get_xfont_device */
  410.     NULL,            /* map_rgb_alpha_color */
  411.     gx_page_device_get_page_device,            /* get_page_device */
  412.     NULL,            /* get_alpha_bits */
  413.     NULL,            /* copy_alpha */
  414.     NULL,            /* get_band */
  415.     NULL,            /* copy_rop */
  416.     NULL,            /* fill_path */
  417.     NULL,            /* stroke_path */
  418.     NULL,            /* fill_mask */
  419.     NULL,            /* fill_trapezoid */
  420.     NULL,            /* fill_parallelogram */
  421.     NULL,            /* fill_triangle */
  422.     NULL,            /* draw_thin_line */
  423.     NULL,            /* begin_image */
  424.     NULL,            /* image_data */
  425.     NULL,            /* end_image */
  426.     NULL,            /* strip_tile_rectangle */
  427.     NULL,            /* strip_copy_rop */
  428. };
  429.  
  430. private gx_device_procs amiga_printer_procs =
  431. {
  432.     amiga_open_printer,
  433.     NULL,            /* get_initial_matrix */
  434.     NULL,            /* sync_output */
  435.     amiga_output_page_printer,
  436.     amiga_close_printer,
  437.     amiga_map_rgb_color,
  438.     amiga_map_color_rgb,
  439.     amiga_fill_rectangle_raw,
  440.     NULL,            /* tile_rectangle */
  441.     amiga_copy_mono_raw,
  442.     amiga_copy_color_raw,
  443.     amiga_draw_line_raw,
  444.     amiga_get_bits,
  445.     amiga_get_params,
  446.     amiga_put_params,
  447.     NULL,            /* map_cmyk_color */
  448.     NULL,            /* get_xfont_procs */
  449.     NULL,            /* get_xfont_device */
  450.     NULL,            /* map_rgb_alpha_color */
  451.     gx_page_device_get_page_device,            /* get_page_device */
  452.     NULL,            /* get_alpha_bits */
  453.     NULL,            /* copy_alpha */
  454.     NULL,            /* get_band */
  455.     NULL,            /* copy_rop */
  456.     NULL,            /* fill_path */
  457.     NULL,            /* stroke_path */
  458.     NULL,            /* fill_mask */
  459.     NULL,            /* fill_trapezoid */
  460.     NULL,            /* fill_parallelogram */
  461.     NULL,            /* fill_triangle */
  462.     NULL,            /* draw_thin_line */
  463.     NULL,            /* begin_image */
  464.     NULL,            /* image_data */
  465.     NULL,            /* end_image */
  466.     NULL,            /* strip_tile_rectangle */
  467.     NULL,            /* strip_copy_rop */
  468. };
  469.  
  470. private gx_device_procs amiga_ilbm_procs =
  471. {
  472.     amiga_open_ilbm,
  473.     NULL,            /* get_initial_matrix */
  474.     NULL,            /* sync_output */
  475.     amiga_output_page_ilbm,
  476.     amiga_close_ilbm,
  477.     amiga_map_rgb_color,
  478.     amiga_map_color_rgb,
  479.     amiga_fill_rectangle_raw,
  480.     NULL,            /* tile_rectangle */
  481.     amiga_copy_mono_raw,
  482.     amiga_copy_color_raw,
  483.     amiga_draw_line_raw,
  484.     amiga_get_bits,
  485.     amiga_get_params,
  486.     amiga_put_params,
  487.     NULL,            /* map_cmyk_color */
  488.     NULL,            /* get_xfont_procs */
  489.     NULL,            /* get_xfont_device */
  490.     NULL,            /* map_rgb_alpha_color */
  491.     gx_page_device_get_page_device,            /* get_page_device */
  492.     NULL,            /* get_alpha_bits */
  493.     NULL,            /* copy_alpha */
  494.     NULL,            /* get_band */
  495.     NULL,            /* copy_rop */
  496.     NULL,            /* fill_path */
  497.     NULL,            /* stroke_path */
  498.     NULL,            /* fill_mask */
  499.     NULL,            /* fill_trapezoid */
  500.     NULL,            /* fill_parallelogram */
  501.     NULL,            /* fill_triangle */
  502.     NULL,            /* draw_thin_line */
  503.     NULL,            /* begin_image */
  504.     NULL,            /* image_data */
  505.     NULL,            /* end_image */
  506.     NULL,            /* strip_tile_rectangle */
  507.     NULL,            /* strip_copy_rop */
  508. };
  509.  
  510.     /* Default device: opens a window on the Workbench screen and renders into it */
  511.  
  512. gx_device_amiga gs_amiga_device =
  513. {
  514.     std_device_std_body(gx_device_amiga, &amiga_default_procs, "amiga", 
  515.         INITIAL_WIDTH, INITIAL_HEIGHT, INITIAL_X_DPI, INITIAL_Y_DPI),
  516.     { 0 },            /* std_procs */
  517.  
  518.     NULL,                /* screen */
  519.     NULL,                /* window */
  520.  
  521.     NULL,                /* super_bitmap */
  522.     NULL,                /* gadget */
  523.     NULL,                /* image */
  524.  
  525.     NULL,                /* dispatcher */
  526.     NULL,                /* main */
  527.  
  528.     NULL,                /* rport */
  529.  
  530.     NULL,                /* printer */
  531.     NULL,                /* port */
  532.     NULL,                /* colormap */
  533.     NULL,                /* bitmap */
  534.     NULL,                /* bitplane */
  535.  
  536.     1,                /* last_pen */
  537.  
  538.     DEFAULT_DISPLAYMODE,    /* display_mode */
  539.     DEFAULT_FILENAME,        /* output file */
  540.     1,                /* page counter */
  541.  
  542.     0,                /* cube_size */
  543.     NULL,                /* temp_rport */
  544.     NULL,                /* temp_array */
  545.     NULL                /* pens */
  546. };
  547.  
  548.     /* Custom device: opens a custom screen, will ask for screen mode or check env variable. */
  549.  
  550. gx_device_amiga gs_amiga_custom_device =
  551. {
  552.     std_device_std_body(gx_device_amiga, &amiga_custom_procs, "amiga_custom", 
  553.         INITIAL_WIDTH, INITIAL_HEIGHT, INITIAL_X_DPI, INITIAL_Y_DPI),
  554.     { 0 },            /* std_procs */
  555.  
  556.     NULL,                /* screen */
  557.     NULL,                /* window */
  558.  
  559.     NULL,                /* super_bitmap */
  560.     NULL,                /* gadget */
  561.     NULL,                /* image */
  562.  
  563.     NULL,                /* dispatcher */
  564.     NULL,                /* main */
  565.  
  566.     NULL,                /* rport */
  567.  
  568.     NULL,                /* printer */
  569.     NULL,                /* port */
  570.     NULL,                /* colormap */
  571.     NULL,                /* bitmap */
  572.     NULL,                /* bitplane */
  573.  
  574.     1,                /* last_pen */
  575.  
  576.     DEFAULT_DISPLAYMODE,    /* display_mode */
  577.     DEFAULT_FILENAME,        /* output file */
  578.     1,                /* page counter */
  579.  
  580.     0,                /* cube_size */
  581.     NULL,                /* temp_rport */
  582.     NULL,                /* temp_array */
  583.     NULL                /* pens */
  584. };
  585.  
  586.     /* Printer device: renders the imagery and sends it to the printer */
  587.  
  588. gx_device_amiga gs_amiga_printer_device =
  589. {
  590.     std_device_std_body(gx_device_amiga, &amiga_printer_procs, "amiga_printer", 
  591.         INITIAL_WIDTH, INITIAL_HEIGHT, INITIAL_X_DPI, INITIAL_Y_DPI),
  592.     { 0 },            /* std_procs */
  593.  
  594.     NULL,                /* screen */
  595.     NULL,                /* window */
  596.  
  597.     NULL,                /* super_bitmap */
  598.     NULL,                /* gadget */
  599.     NULL,                /* image */
  600.  
  601.     NULL,                /* dispatcher */
  602.     NULL,                /* main */
  603.  
  604.     NULL,                /* rport */
  605.  
  606.     NULL,                /* printer */
  607.     NULL,                /* port */
  608.     NULL,                /* colormap */
  609.     NULL,                /* bitmap */
  610.     NULL,                /* bitplane */
  611.  
  612.     1,                /* last_pen */
  613.  
  614.     DEFAULT_DISPLAYMODE,    /* display_mode */
  615.     DEFAULT_FILENAME,        /* output file */
  616.     1,                /* page counter */
  617.  
  618.     0,                /* cube_size */
  619.     NULL,                /* temp_rport */
  620.     NULL,                /* temp_array */
  621.     NULL                /* pens */
  622. };
  623.  
  624.     /* ILBM device: renders the imagery and saves it to an IFF-ILBM file. */
  625.  
  626. gx_device_amiga gs_amiga_ilbm_device =
  627. {
  628.     std_device_std_body(gx_device_amiga, &amiga_ilbm_procs, "amiga_ilbm", 
  629.         INITIAL_WIDTH, INITIAL_HEIGHT, INITIAL_X_DPI, INITIAL_Y_DPI),
  630.     { 0 },            /* std_procs */
  631.  
  632.     NULL,                /* screen */
  633.     NULL,                /* window */
  634.  
  635.     NULL,                /* super_bitmap */
  636.     NULL,                /* gadget */
  637.     NULL,                /* image */
  638.  
  639.     NULL,                /* dispatcher */
  640.     NULL,                /* main */
  641.  
  642.     NULL,                /* rport */
  643.  
  644.     NULL,                /* printer */
  645.     NULL,                /* port */
  646.     NULL,                /* colormap */
  647.     NULL,                /* bitmap */
  648.     NULL,                /* bitplane */
  649.  
  650.     1,                /* last_pen */
  651.  
  652.     DEFAULT_DISPLAYMODE,    /* display_mode */
  653.     DEFAULT_FILENAME,        /* output file */
  654.     1,                /* page counter */
  655.  
  656.     0,                /* cube_size */
  657.     NULL,                /* temp_rport */
  658.     NULL,                /* temp_array */
  659.     NULL                /* pens */
  660. };
  661.  
  662.     /* set_mono_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  663.      *
  664.      *    Reconfigure a device for monochrome output.
  665.      */
  666.  
  667. private VOID
  668. set_mono_device(gx_device_amiga *dev)
  669. {
  670.     xdev -> color_info . num_components    = 1;
  671.     xdev -> color_info . depth            = 1;
  672.     xdev -> color_info . max_gray        = 1;
  673.     xdev -> color_info . max_color        = 0;
  674.     xdev -> color_info . dither_grays    = 2;
  675.     xdev -> color_info . dither_colors    = 0;
  676.  
  677.     xdev -> std_procs . copy_color        = amiga_copy_color;
  678.     xdev -> std_procs . map_rgb_color    = amiga_map_rgb_color;
  679.     xdev -> std_procs . map_color_rgb    = amiga_map_color_rgb;
  680.  
  681.     xdev -> cube_size                    = 0;
  682. }
  683.  
  684.     /* set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  685.      *
  686.      *    Reconfigure a device for colour output.
  687.      */
  688.  
  689. private VOID
  690. set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens)
  691. {
  692.     xdev -> color_info . num_components    = 3;
  693.     xdev -> color_info . depth            = 8;
  694.     xdev -> color_info . max_gray        = cube_size - 1;
  695.     xdev -> color_info . max_color        = cube_size - 1;
  696.     xdev -> color_info . dither_grays    = cube_size;
  697.     xdev -> color_info . dither_colors    = cube_size;
  698.  
  699.     xdev -> std_procs . copy_color        = amiga_copy_color8;
  700.  
  701.         /* Any colours to be remapped? */
  702.  
  703.     if(pens)
  704.     {
  705.         xdev -> std_procs . map_rgb_color    = amiga_color_map_rgb_color_pen;
  706.         xdev -> std_procs . map_color_rgb    = amiga_color_map_color_rgb_pen;
  707.         xdev -> pens                        = pens;
  708.     }
  709.     else
  710.     {
  711.         xdev -> std_procs . map_rgb_color    = amiga_color_map_rgb_color;
  712.         xdev -> std_procs . map_color_rgb    = amiga_color_map_color_rgb;
  713.     }
  714.  
  715.         /* Remember the size of the RGB cube. */
  716.  
  717.     xdev -> cube_size                    = cube_size;
  718. }
  719.  
  720.     /* set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize):
  721.      *
  722.      *    Configure the printer device for colour output.
  723.      */
  724.  
  725. private VOID
  726. set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize)
  727. {
  728.     xdev -> color_info . num_components    = 3;
  729.     xdev -> color_info . depth            = 16;
  730.     xdev -> color_info . max_gray        = CubeSize - 1;
  731.     xdev -> color_info . max_color        = CubeSize - 1;
  732.     xdev -> color_info . dither_grays    = CubeSize;
  733.     xdev -> color_info . dither_colors    = CubeSize;
  734.  
  735.     xdev -> std_procs . fill_rectangle    = amiga_fill_rectangle_raw_color;
  736.     xdev -> std_procs . copy_mono        = amiga_copy_mono_raw_color;
  737.     xdev -> std_procs . copy_color        = amiga_copy_color_raw_color16;
  738.     xdev -> std_procs . draw_line        = amiga_draw_line_raw_color;
  739.     xdev -> std_procs . map_rgb_color    = amiga_color_map_rgb_color;
  740.     xdev -> std_procs . map_color_rgb    = amiga_color_map_color_rgb;
  741.     xdev -> cube_size                    = CubeSize;
  742. }
  743.  
  744.     /* DeleteBitMap(struct BitMap *BitMap,BOOL Private):
  745.      *
  746.      *    Free memory associated with a custom rendering bitmap.
  747.      */
  748.  
  749. private VOID
  750. DeleteBitMap(struct BitMap *BitMap,BOOL Private)
  751. {
  752.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  753.         FreeBitMap(BitMap);
  754.     else
  755.     {
  756.         LONG i;
  757.  
  758.         for(i = 0 ; i < BitMap -> Depth ; i++)
  759.         {
  760.             if(BitMap -> Planes[i])
  761.                 FreeVec(BitMap -> Planes[i]);
  762.         }
  763.  
  764.         FreeVec(BitMap);
  765.     }
  766. }
  767.  
  768.     /* CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private):
  769.      *
  770.      *    Create a custom rendering bitmap.
  771.      */
  772.  
  773. private struct BitMap *
  774. CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private)
  775. {
  776.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  777.         return(AllocBitMap(Width,Height,Depth,Flags,Friend));
  778.     else
  779.     {
  780.         struct BitMap    *BitMap;
  781.         LONG         Plus;
  782.         ULONG         MemType;
  783.  
  784.             /* Bitmap structure needs to be padded if more
  785.              * than the standard eight bitplanes are to be
  786.              * allocated.
  787.              */
  788.  
  789.         if(Depth > 8)
  790.             Plus = (Depth - 8) * sizeof(PLANEPTR);
  791.         else
  792.             Plus = 0;
  793.  
  794.         if(Private)
  795.             MemType = MEMF_ANY;
  796.         else
  797.             MemType = MEMF_CHIP;
  798.  
  799.         BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap) + Plus, 
  800.             MEMF_ANY | MEMF_CLEAR);
  801.         if(BitMap)
  802.         {
  803.             LONG i,PageSize;
  804.  
  805.             InitBitMap(BitMap,Depth,Width,Height);
  806.  
  807.             PageSize = BitMap -> BytesPerRow * BitMap -> Rows;
  808.  
  809.             for(i = 0 ; i < BitMap -> Depth ; i++)
  810.             {
  811.                 if(!(BitMap -> Planes[i] = (PLANEPTR)AllocVec(PageSize,MemType)))
  812.                 {
  813.                     LONG j;
  814.  
  815.                     for(j = 0 ; j < i ; j++)
  816.                         FreeVec(BitMap -> Planes[j]);
  817.  
  818.                     FreeVec(BitMap);
  819.  
  820.                     return(NULL);
  821.                 }
  822.             }
  823.  
  824.             return(BitMap);
  825.         }
  826.         else
  827.         {
  828.             return(NULL);
  829.         }
  830.     }
  831. }
  832.  
  833.     /* DeleteTempRPort(struct RastPort *Temp):
  834.      *
  835.      *    Free memory associated with a temporary raster port.
  836.      */
  837.  
  838. private VOID
  839. DeleteTempRPort(struct RastPort *Temp)
  840. {
  841.     DeleteBitMap(Temp -> BitMap,FALSE);
  842.  
  843.     FreeVec(Temp);
  844. }
  845.  
  846.     /* CreateTempRPort(struct RastPort *Source):
  847.      *
  848.      *    Allocate memory for temporary raster port (one line high).
  849.      */
  850.  
  851. private struct RastPort *
  852. CreateTempRPort(struct RastPort *Source)
  853. {
  854.     struct RastPort *Temp;
  855.  
  856.     Temp = (struct RastPort *)AllocVec(sizeof(struct RastPort), MEMF_ANY);
  857.     if(Temp)
  858.     {
  859.         LONG Width,Depth;
  860.  
  861.         CopyMem(Source,Temp,sizeof(struct RastPort));
  862.  
  863.         Temp -> Layer = NULL;
  864.  
  865.         if(GfxBase -> LibNode . lib_Version >= 39)
  866.         {
  867.             Width    = GetBitMapAttr(Source -> BitMap,BMA_WIDTH);
  868.             Depth    = GetBitMapAttr(Source -> BitMap,BMA_DEPTH);
  869.         }
  870.         else
  871.         {
  872.             Width    = Source -> BitMap -> BytesPerRow * 8;
  873.             Depth    = Source -> BitMap -> Depth;
  874.         }
  875.  
  876.         Temp->BitMap = CreateBitMap(Width, 1, Depth, NULL, Source->BitMap, 
  877.             FALSE);
  878.         if(Temp -> BitMap)
  879.             return(Temp);
  880.         else
  881.             FreeVec(Temp);
  882.     }
  883.  
  884.     return(NULL);
  885. }
  886.  
  887.     /* Euclid(LONG a,LONG b):
  888.      *
  889.      *    Compute the greatest common divisor of two integers.
  890.      */
  891.  
  892. private LONG
  893. Euclid(LONG a,LONG b)
  894. {
  895.     do
  896.     {
  897.         if(a < b)
  898.         {
  899.             LONG t;
  900.  
  901.             t = a;
  902.             a = b;
  903.             b = t;
  904.         }
  905.  
  906.         a = a % b;
  907.     }
  908.     while(a);
  909.  
  910.     return(b);
  911. }
  912.  
  913.     /* PutDump(register BYTE *Destination,register LONG Count):
  914.      *
  915.      *    Store a byte dump.
  916.      */
  917.  
  918. private BYTE *
  919. PutDump(register BYTE *Destination,register LONG Count)
  920. {
  921.     register BYTE *Source = Buffer;
  922.  
  923.     *Destination++     = Count - 1;
  924.      PackedBytes    += Count + 1;
  925.  
  926.     while(Count--)
  927.         *Destination++ = *Source++;
  928.  
  929.     return(Destination);
  930. }
  931.  
  932.     /* PutRun(register BYTE *Destination,LONG Count,WORD Char):
  933.      *
  934.      *    Store a byte run.
  935.      */
  936.  
  937. private BYTE *
  938. PutRun(register BYTE *Destination,LONG Count,WORD Char)
  939. {
  940.     *Destination++     = -(Count - 1);
  941.     *Destination++     = Char;
  942.      PackedBytes    += 2;
  943.  
  944.     return(Destination);
  945. }
  946.  
  947.     /* PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize):
  948.      *
  949.      *    Pack a raster line using the CmpByteRun1 algorithm.
  950.      */
  951.  
  952. private LONG
  953. PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize)
  954. {
  955.     register BYTE *Source = *SourcePtr;
  956.  
  957.     WORD    Buffered    = 1,
  958.         RunStart    = 0;
  959.     BYTE    Mode        = DUMP,
  960.         LastChar,
  961.         Char;
  962.  
  963.     PackedBytes = 0;
  964.  
  965.     Buffer[0] = LastChar = Char = *Source++;
  966.  
  967.     RowSize--;
  968.  
  969.     while(RowSize--)
  970.     {
  971.         Buffer[Buffered++] = Char = *Source++;
  972.  
  973.         if(Mode)
  974.         {
  975.             if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
  976.             {
  977.                 Destination    = PutRun(Destination,Buffered - 1 - RunStart,LastChar);
  978.                 Buffer[0]    = Char;
  979.                 Buffered    = 1;
  980.                 RunStart    = 0;
  981.                 Mode        = DUMP;
  982.             }
  983.         }
  984.         else
  985.         {
  986.             if(Buffered > MAXDAT)
  987.             {
  988.                 Destination    = PutDump(Destination,Buffered - 1);
  989.                 Buffer[0]    = Char;
  990.                 Buffered    = 1;
  991.                 RunStart    = 0;
  992.             }
  993.             else
  994.             {
  995.                 if(Char == LastChar)
  996.                 {
  997.                     if(Buffered - RunStart >= MINRUN)
  998.                     {
  999.                         if(RunStart)
  1000.                             Destination = PutDump(Destination,RunStart);
  1001.  
  1002.                         Mode = RUN;
  1003.                     }
  1004.                     else
  1005.                     {
  1006.                         if(!RunStart)
  1007.                             Mode = RUN;
  1008.                     }
  1009.                 }
  1010.                 else
  1011.                     RunStart = Buffered - 1;
  1012.             }
  1013.         }
  1014.  
  1015.         LastChar = Char;
  1016.     }
  1017.  
  1018.     if(Mode)
  1019.         PutRun(Destination,Buffered - RunStart,LastChar);
  1020.     else
  1021.         PutDump(Destination,Buffered);
  1022.  
  1023.     *SourcePtr = Source;
  1024.  
  1025.     return(PackedBytes);
  1026. }
  1027.  
  1028.     /* PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap):
  1029.      *
  1030.      *    Store a bitmap in a BODY chunk.
  1031.      */
  1032.  
  1033. private BOOL
  1034. PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap)
  1035. {
  1036.     PLANEPTR    *Planes;
  1037.     BYTE        *PackBuffer;
  1038.     BOOL         Success = FALSE;
  1039.     LONG         PackedBytes,
  1040.              i,j;
  1041.  
  1042.         /* Allocate the bitplane information. */
  1043.  
  1044.     Planes = (PLANEPTR *)AllocVec(BitMap->Depth * sizeof(PLANEPTR *), 
  1045.         MEMF_ANY | MEMF_CLEAR);
  1046.     if(Planes)
  1047.     {
  1048.             /* Allocate the compression buffer. */
  1049.  
  1050.         PackBuffer = (BYTE *)AllocVec(BitMap->BytesPerRow * 2, MEMF_ANY);
  1051.         if(PackBuffer)
  1052.         {
  1053.                 /* Copy the planes over. */
  1054.  
  1055.             for(i = 0 ; i < BitMap -> Depth ; i++)
  1056.                 Planes[i] = BitMap -> Planes[i];
  1057.  
  1058.             if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  1059.             {
  1060.                 Success = TRUE;
  1061.  
  1062.                     /* Run down the rows. */
  1063.  
  1064.                 for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  1065.                 {
  1066.                     for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  1067.                     {
  1068.                             /* Pack the data. */
  1069.  
  1070.                         PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
  1071.  
  1072.                             /* Write it to disk. */
  1073.  
  1074.                         if(WriteChunkRecords(Handle,PackBuffer,PackedBytes,1) != 1)
  1075.                             Success = FALSE;
  1076.                     }
  1077.                 }
  1078.  
  1079.                 if(PopChunk(Handle))
  1080.                     Success = FALSE;
  1081.             }
  1082.  
  1083.             FreeVec(PackBuffer);
  1084.         }
  1085.  
  1086.         FreeVec(Planes);
  1087.     }
  1088.  
  1089.     return(Success);
  1090. }
  1091.  
  1092.     /* PutANNO(struct IFFHandle *Handle):
  1093.      *
  1094.      *    Store annotation chunk.
  1095.      */
  1096.  
  1097. private BOOL
  1098. PutANNO(struct IFFHandle *Handle)
  1099. {
  1100.     STATIC unsigned char Note[256];
  1101.  
  1102.     sprintf(Note, "Image generated by %s %d.%02d (device=amiga_ilbm)", 
  1103.         gs_product, (int)(gs_revision / 100), (int)(gs_revision % 100));
  1104.  
  1105.     if(!PushChunk(Handle,0,ID_ANNO,strlen(Note)))
  1106.     {
  1107.         if(WriteChunkRecords(Handle,Note,strlen(Note),1) == 1)
  1108.         {
  1109.             if(!PopChunk(Handle))
  1110.                 return(TRUE);
  1111.         }
  1112.     }
  1113.  
  1114.     return(FALSE);
  1115. }
  1116.  
  1117.     /* PutCAMG(struct IFFHandle *Handle):
  1118.      *
  1119.      *    Store display mode chunk.
  1120.      */
  1121.  
  1122. private BOOL
  1123. PutCAMG(struct IFFHandle *Handle)
  1124. {
  1125.     ULONG ViewModes = HIRESLACE_KEY;
  1126.  
  1127.     if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
  1128.     {
  1129.         if(WriteChunkRecords(Handle,&ViewModes,sizeof(ULONG),1) == 1)
  1130.         {
  1131.             if(!PopChunk(Handle))
  1132.                 return(TRUE);
  1133.         }
  1134.     }
  1135.  
  1136.     return(FALSE);
  1137. }
  1138.  
  1139.     /* PutCMAP(struct IFFHandle *Handle):
  1140.      *
  1141.      *    Store colour map chunk.
  1142.      */
  1143.  
  1144. private BOOL
  1145. PutCMAP(struct IFFHandle *Handle)
  1146. {
  1147.     STATIC UBYTE Colours[2][3] =
  1148.     {
  1149.         { 0x00,0x00,0x00, },
  1150.         { 0xFF,0xFF,0xFF, },
  1151.     };
  1152.  
  1153.     if(!PushChunk(Handle,0,ID_CMAP,sizeof(Colours)))
  1154.     {
  1155.         if(WriteChunkRecords(Handle,Colours,2,3) == 3)
  1156.         {
  1157.             if(!PopChunk(Handle))
  1158.                 return(TRUE);
  1159.         }
  1160.     }
  1161.  
  1162.     return(FALSE);
  1163. }
  1164.  
  1165.     /* PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI):
  1166.      *
  1167.      *    Store DPI chunk.
  1168.      */
  1169.  
  1170. private BOOL
  1171. PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI)
  1172. {
  1173.     DPIHeader Header;
  1174.  
  1175.     Header . dpi_x = X_DPI;
  1176.     Header . dpi_y = Y_DPI;
  1177.  
  1178.     if(!PushChunk(Handle,0,ID_DPI,sizeof(Header)))
  1179.     {
  1180.         if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1181.         {
  1182.             if(!PopChunk(Handle))
  1183.                 return(TRUE);
  1184.         }
  1185.     }
  1186.  
  1187.     return(FALSE);
  1188. }
  1189.  
  1190.     /* PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1191.      *
  1192.      *    Store BMHD chunk.
  1193.      */
  1194.  
  1195. private BOOL
  1196. PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1197. {
  1198.         /* Valid parameters? */
  1199.  
  1200.     if(X_DPI > 0 && Y_DPI > 0 && Width > 0 && Height > 0)
  1201.     {
  1202.         struct BitMapHeader    Header;
  1203.         UWORD        gcd;
  1204.  
  1205.             /* So we can store neat & small
  1206.              * aspect ration values.
  1207.              */
  1208.  
  1209.         gcd = Euclid(X_DPI,Y_DPI);
  1210.  
  1211.         Header . bmh_Width            = Width;
  1212.         Header . bmh_Height            = Height;
  1213.         Header . bmh_Left            = 0;
  1214.         Header . bmh_Top            = 0;
  1215.         Header . bmh_Depth            = 1;
  1216.         Header . bmh_Masking        = 0;
  1217.         Header . bmh_Compression    = 1;
  1218.         Header . bmh_Pad            = 0;
  1219.         Header . bmh_Transparent    = 0;
  1220.         Header . bmh_XAspect        = X_DPI / gcd;
  1221.         Header . bmh_YAspect        = Y_DPI / gcd;
  1222.         Header . bmh_PageWidth        = Width;
  1223.         Header . bmh_PageHeight        = Height;
  1224.  
  1225.         if(!PushChunk(Handle,0,ID_BMHD,sizeof(Header)))
  1226.         {
  1227.             if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1228.             {
  1229.                 if(!PopChunk(Handle))
  1230.                     return(TRUE);
  1231.             }
  1232.         }
  1233.     }
  1234.  
  1235.     return(FALSE);
  1236. }
  1237.  
  1238.     /* SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1239.      *
  1240.      *    Store a bitmap in an IFF-ILBM file.
  1241.      */
  1242.  
  1243. private BOOL
  1244. SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1245. {
  1246.     struct IFFHandle    *Handle;
  1247.     BOOL             Success = FALSE;
  1248.  
  1249.     Handle = AllocIFF();
  1250.     if(Handle)
  1251.     {
  1252.         Handle -> iff_Stream = Open(Name, MODE_NEWFILE);
  1253.         if(Handle)
  1254.         {
  1255.             InitIFFasDOS(Handle);
  1256.  
  1257.             if(!OpenIFF(Handle,IFFF_WRITE))
  1258.             {
  1259.                 if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
  1260.                 {
  1261.                     if(PutBMHD(Handle,Width,Height,X_DPI,Y_DPI))
  1262.                     {
  1263.                         if(PutANNO(Handle))
  1264.                         {
  1265.                             if(PutCMAP(Handle))
  1266.                             {
  1267.                                 if(PutCAMG(Handle))
  1268.                                 {
  1269.                                     if(PutDPI(Handle,X_DPI,Y_DPI))
  1270.                                     {
  1271.                                         if(PutBODY(Handle,BitMap))
  1272.                                             Success = TRUE;
  1273.                                     }
  1274.                                 }
  1275.                             }
  1276.                         }
  1277.                     }
  1278.  
  1279.                     if(PopChunk(Handle))
  1280.                         Success = FALSE;
  1281.                 }
  1282.  
  1283.                 CloseIFF(Handle);
  1284.             }
  1285.  
  1286.             Close(Handle -> iff_Stream);
  1287.  
  1288.             if(!Success)
  1289.                 DeleteFile(Name);
  1290.         }
  1291.  
  1292.         FreeIFF(Handle);
  1293.     }
  1294.  
  1295.     return(Success);
  1296. }
  1297.  
  1298.     /* DispatchTask():
  1299.      *
  1300.      *    Asynchronous window message dispatcher.
  1301.      */
  1302.  
  1303. private VOID
  1304. DispatchTask()
  1305. {
  1306.     struct Task    *me;
  1307.     gx_device    *dev;
  1308.  
  1309.         /* Set up global data area base register. */
  1310. #ifdef IXEMUL
  1311.     ix_geta4();
  1312. #endif
  1313.         /* Who am I? */
  1314.  
  1315.     me = FindTask(NULL);
  1316.  
  1317.         /* Wait for wakeup call. */
  1318.  
  1319.     Wait(SIG_WAKEUP);
  1320.  
  1321.         /* Obtain device pointer. */
  1322.  
  1323.     dev = me -> tc_UserData;
  1324.  
  1325.         /* Enable user input. */
  1326.  
  1327.     if(ModifyIDCMP(xdev -> window,IDCMP_FLAGS))
  1328.     {
  1329.         ULONG    Mask = 1 << xdev -> window -> UserPort -> mp_SigBit,
  1330.             Set;
  1331.         BOOL    Done = FALSE;
  1332.  
  1333.             /* Fill in the dispatcher entry. */
  1334.  
  1335.         xdev -> dispatcher = me;
  1336.  
  1337.             /* Ring back. */
  1338.  
  1339.         Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1340.  
  1341.             /* Wait for input... */
  1342.  
  1343.         do
  1344.         {
  1345.             Set = Wait(Mask | SIG_KILL);
  1346.  
  1347.             if(Set & Mask)
  1348.                 DispatchSuperWindow(dev);
  1349.  
  1350.             if(Set & SIG_KILL)
  1351.                 Done = TRUE;
  1352.         }
  1353.         while(!Done);
  1354.  
  1355.             /* Disable user input. */
  1356.  
  1357.         ModifyIDCMP(xdev -> window,NULL);
  1358.     }
  1359.  
  1360.         /* Disable task switching. */
  1361.  
  1362.     Forbid();
  1363.  
  1364.         /* Clear the dispatcher entry. */
  1365.  
  1366.     xdev -> dispatcher = NULL;
  1367.  
  1368.         /* Signal the main process that we are done. */
  1369.  
  1370.     Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1371.  
  1372.         /* Enable task switching. */
  1373.  
  1374.     Permit();
  1375.  
  1376.         /* Remove ourselves. */
  1377.  
  1378.     RemTask(NULL);
  1379. }
  1380.  
  1381.     /* DeleteScrollers(gx_device *dev):
  1382.      *
  1383.      *    Delete the window border scrollers.
  1384.      */
  1385.  
  1386. private VOID
  1387. DeleteScrollers(gx_device *dev)
  1388. {
  1389.     if(xdev -> gadget)
  1390.     {
  1391.         if(xdev -> gadget[HORIZONTAL_SCROLLER])
  1392.             DisposeObject(xdev -> gadget[HORIZONTAL_SCROLLER]);
  1393.  
  1394.         if(xdev -> gadget[VERTICAL_SCROLLER])
  1395.             DisposeObject(xdev -> gadget[VERTICAL_SCROLLER]);
  1396.  
  1397.         if(xdev -> gadget[UP_ARROW])
  1398.             DisposeObject(xdev -> gadget[UP_ARROW]);
  1399.  
  1400.         if(xdev -> gadget[DOWN_ARROW])
  1401.             DisposeObject(xdev -> gadget[DOWN_ARROW]);
  1402.  
  1403.         if(xdev -> gadget[LEFT_ARROW])
  1404.             DisposeObject(xdev -> gadget[LEFT_ARROW]);
  1405.  
  1406.         if(xdev -> gadget[RIGHT_ARROW])
  1407.             DisposeObject(xdev -> gadget[RIGHT_ARROW]);
  1408.  
  1409.         FreeVec(xdev -> gadget);
  1410.  
  1411.         xdev -> gadget = NULL;
  1412.     }
  1413.  
  1414.     if(xdev -> image)
  1415.     {
  1416.         if(xdev -> image[UP_IMAGE])
  1417.             DisposeObject(xdev -> image[UP_IMAGE]);
  1418.  
  1419.         if(xdev -> image[DOWN_IMAGE])
  1420.             DisposeObject(xdev -> image[DOWN_IMAGE]);
  1421.  
  1422.         if(xdev -> image[LEFT_IMAGE])
  1423.             DisposeObject(xdev -> image[LEFT_IMAGE]);
  1424.  
  1425.         if(xdev -> image[RIGHT_IMAGE])
  1426.             DisposeObject(xdev -> image[RIGHT_IMAGE]);
  1427.  
  1428.         FreeVec(xdev -> image);
  1429.  
  1430.         xdev -> image = NULL;
  1431.     }
  1432. }
  1433.  
  1434.     /* CreateScrollers(gx_device *dev,struct Screen *Screen):
  1435.      *
  1436.      *    Create the window border scroller handles.
  1437.      */
  1438.  
  1439. private BOOL
  1440. CreateScrollers(gx_device *dev,struct Screen *Screen)
  1441. {
  1442.     BOOL Result = FALSE;
  1443.  
  1444.     xdev -> gadget = (struct Gadget **)AllocVec(sizeof(struct Gadget *) 
  1445.         * GADGET_COUNT, MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC);
  1446.     if(xdev -> gadget)
  1447.     {
  1448.         xdev -> image = (struct Image **)AllocVec(sizeof(struct Image *) 
  1449.             * IMAGE_COUNT, MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC);
  1450.         if(xdev -> image)
  1451.         {
  1452.             struct DrawInfo *DrawInfo;
  1453.  
  1454.             DrawInfo = GetScreenDrawInfo(Screen);
  1455.             if(DrawInfo)
  1456.             {
  1457.                 ULONG     SizeWidth,
  1458.                      SizeHeight;
  1459.                 ULONG     ArrowWidth,
  1460.                      ArrowHeight;
  1461.                 UWORD     SizeType;
  1462.                 Object    *SizeImage;
  1463.  
  1464.                 if(Screen -> Flags & SCREENHIRES)
  1465.                 {
  1466.                     SizeWidth    = 18;
  1467.                     SizeHeight    = 10;
  1468.  
  1469.                     SizeType    = SYSISIZE_MEDRES;
  1470.                 }
  1471.                 else
  1472.                 {
  1473.                     SizeWidth    = 13;
  1474.                     SizeHeight    = 11;
  1475.  
  1476.                     SizeType    = SYSISIZE_LOWRES;
  1477.                 }
  1478.  
  1479.                 SizeImage = NewObject(NULL, SYSICLASS, 
  1480.                     SYSIA_Size,    SizeType,
  1481.                     SYSIA_Which,    SIZEIMAGE,
  1482.                     SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1483.                     TAG_DONE);
  1484.                 if(SizeImage)
  1485.                 {
  1486.                     GetAttr(IA_Width,    SizeImage,&SizeWidth);
  1487.                     GetAttr(IA_Height,    SizeImage,&SizeHeight);
  1488.  
  1489.                     DisposeObject(SizeImage);
  1490.                 }
  1491.  
  1492.                 xdev -> image[UP_IMAGE] = (struct Image *)NewObject(NULL, SYSICLASS,
  1493.                     SYSIA_Size,    SizeType,
  1494.                     SYSIA_Which,    UPIMAGE,
  1495.                     SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1496.                     TAG_DONE);
  1497.                 if(xdev -> image[UP_IMAGE])
  1498.                 {
  1499.                     GetAttr(IA_Height,xdev -> image[UP_IMAGE],&ArrowHeight);
  1500.  
  1501.                     xdev -> image[DOWN_IMAGE] = (struct Image *)NewObject(NULL, SYSICLASS,
  1502.                         SYSIA_Size,    SizeType,
  1503.                         SYSIA_Which,    DOWNIMAGE,
  1504.                         SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1505.                         TAG_DONE);
  1506.                     if(xdev -> image[DOWN_IMAGE])
  1507.                     {
  1508.                         xdev -> image[LEFT_IMAGE] = (struct Image *)NewObject(NULL, SYSICLASS,
  1509.                             SYSIA_Size,    SizeType,
  1510.                             SYSIA_Which,    LEFTIMAGE,
  1511.                             SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1512.                             TAG_DONE);
  1513.                         if(xdev -> image[LEFT_IMAGE])
  1514.                         {
  1515.                             GetAttr(IA_Width,xdev -> image[LEFT_IMAGE],&ArrowWidth);
  1516.  
  1517.                             xdev -> image[RIGHT_IMAGE] = (struct Image *)NewObject(NULL, SYSICLASS,
  1518.                                 SYSIA_Size,    SizeType,
  1519.                                 SYSIA_Which,    RIGHTIMAGE,
  1520.                                 SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1521.                                 TAG_DONE);
  1522.                             if(xdev -> image[RIGHT_IMAGE])
  1523.                             {
  1524.                                 xdev -> gadget[VERTICAL_SCROLLER] = NewObject(NULL, PROPGCLASS,
  1525.                                     GA_ID,        VERTICAL_SCROLLER,
  1526.  
  1527.                                     GA_Top,        Screen -> WBorTop + Screen -> Font -> ta_YSize + 2,
  1528.                                     GA_RelHeight,    -(Screen -> WBorTop + Screen -> Font -> ta_YSize + 2 + SizeHeight + 1 + 2 * ArrowHeight),
  1529.                                     GA_Width,    SizeWidth - 8,
  1530.                                     GA_RelRight,    -(SizeWidth - 5),
  1531.  
  1532.                                     GA_GZZGadget,    TRUE,
  1533.                                     GA_Immediate,    TRUE,
  1534.                                     GA_FollowMouse,    TRUE,
  1535.                                     GA_RelVerify,    TRUE,
  1536.                                     GA_RightBorder,    TRUE,
  1537.  
  1538.                                     PGA_Freedom,    FREEVERT,
  1539.                                     PGA_NewLook,    TRUE,
  1540.                                     PGA_Borderless,    TRUE,
  1541.  
  1542.                                     PGA_Visible,    1,
  1543.                                     PGA_Total,    1,
  1544.                                     TAG_DONE);
  1545.                                 if(xdev -> gadget[VERTICAL_SCROLLER])
  1546.                                 {
  1547.                                     xdev -> gadget[HORIZONTAL_SCROLLER] = NewObject(NULL, PROPGCLASS,
  1548.                                         GA_ID,        HORIZONTAL_SCROLLER,
  1549.                                         GA_Previous,    (ULONG)(xdev -> gadget[VERTICAL_SCROLLER]),
  1550.  
  1551.                                         GA_Height,    SizeHeight - 4,
  1552.                                         GA_RelBottom,    -(SizeHeight - 4 + 1),
  1553.                                         GA_Left,    4,
  1554.                                         GA_RelWidth,    -(2 + SizeWidth + 4 + 2 * ArrowWidth),
  1555.  
  1556.                                         GA_GZZGadget,    TRUE,
  1557.                                         GA_Immediate,    TRUE,
  1558.                                         GA_FollowMouse,    TRUE,
  1559.                                         GA_RelVerify,    TRUE,
  1560.                                         GA_BottomBorder,TRUE,
  1561.  
  1562.                                         PGA_Freedom,    FREEHORIZ,
  1563.                                         PGA_NewLook,    TRUE,
  1564.                                         PGA_Borderless,    TRUE,
  1565.  
  1566.                                         PGA_Visible,    1,
  1567.                                         PGA_Total,    1,
  1568.                                         TAG_DONE);
  1569.                                     if(xdev -> gadget[HORIZONTAL_SCROLLER])
  1570.                                     {
  1571.                                         STATIC struct TagItem ArrowMappings[] = 
  1572.                                         { 
  1573.                                             { GA_ID, GA_ID, },
  1574.                                             { TAG_END, },
  1575.                                         };
  1576.  
  1577.                                         xdev -> gadget[UP_ARROW] = NewObject(NULL, BUTTONGCLASS,
  1578.                                             GA_ID,        UP_ARROW,
  1579.                                             GA_Previous,    (ULONG)(xdev -> gadget[HORIZONTAL_SCROLLER]),
  1580.  
  1581.                                             GA_GZZGadget,    TRUE,
  1582.                                             GA_Image,    (ULONG)(xdev -> image[UP_IMAGE]),
  1583.                                             GA_RelRight,    -(SizeWidth - 1),
  1584.                                             GA_RelBottom,    -(SizeHeight - 1 + 2 * ArrowHeight),
  1585.                                             GA_Height,    ArrowHeight,
  1586.                                             GA_Width,    SizeWidth,
  1587.                                             GA_Immediate,    TRUE,
  1588.                                             GA_RelVerify,    TRUE,
  1589.                                             GA_RightBorder,    TRUE,
  1590.  
  1591.                                             ICA_TARGET,    ICTARGET_IDCMP,
  1592.                                             ICA_MAP,    (ULONG)ArrowMappings,
  1593.                                             TAG_DONE);
  1594.                                         if(xdev -> gadget[UP_ARROW])
  1595.                                         {
  1596.                                             xdev -> gadget[DOWN_ARROW] = NewObject(NULL, BUTTONGCLASS,
  1597.                                                 GA_ID,        DOWN_ARROW,
  1598.                                                 GA_Previous,    (ULONG)(xdev -> gadget[UP_ARROW]),
  1599.  
  1600.                                                 GA_GZZGadget,    TRUE,
  1601.                                                 GA_Image,    (ULONG)(xdev -> image[DOWN_IMAGE]),
  1602.                                                 GA_RelRight,    -(SizeWidth - 1),
  1603.                                                 GA_RelBottom,    -(SizeHeight - 1 + ArrowHeight),
  1604.                                                 GA_Height,    ArrowHeight,
  1605.                                                 GA_Width,    SizeWidth,
  1606.                                                 GA_Immediate,    TRUE,
  1607.                                                 GA_RelVerify,    TRUE,
  1608.                                                 GA_RightBorder,    TRUE,
  1609.  
  1610.                                                 ICA_TARGET,    ICTARGET_IDCMP,
  1611.                                                 ICA_MAP,    (ULONG)ArrowMappings,
  1612.                                                 TAG_DONE);
  1613.                                             if(xdev -> gadget[DOWN_ARROW])
  1614.                                             {
  1615.                                                 xdev -> gadget[LEFT_ARROW] = NewObject(NULL, BUTTONGCLASS,
  1616.                                                     GA_ID,        LEFT_ARROW,
  1617.                                                     GA_Previous,    (ULONG)(xdev -> gadget[DOWN_ARROW]),
  1618.  
  1619.                                                     GA_GZZGadget,    TRUE,
  1620.                                                     GA_Image,    (ULONG)(xdev -> image[LEFT_IMAGE]),
  1621.                                                     GA_RelRight,    -(SizeWidth - 1 + 2 * ArrowWidth),
  1622.                                                     GA_RelBottom,    -(SizeHeight - 1),
  1623.                                                     GA_Height,    SizeHeight,
  1624.                                                     GA_Width,    ArrowWidth,
  1625.                                                     GA_Immediate,    TRUE,
  1626.                                                     GA_RelVerify,    TRUE,
  1627.                                                     GA_BottomBorder,TRUE,
  1628.  
  1629.                                                     ICA_TARGET,    ICTARGET_IDCMP,
  1630.                                                     ICA_MAP,    (ULONG)ArrowMappings,
  1631.                                                     TAG_DONE);
  1632.                                                 if(xdev -> gadget[LEFT_ARROW])
  1633.                                                 {
  1634.                                                     xdev -> gadget[RIGHT_ARROW] = NewObject(NULL, BUTTONGCLASS,
  1635.                                                         GA_ID,        RIGHT_ARROW,
  1636.                                                         GA_Previous,    (ULONG)(xdev -> gadget[LEFT_ARROW]),
  1637.  
  1638.                                                         GA_GZZGadget,    TRUE,
  1639.                                                         GA_Image,    (ULONG)(xdev -> image[RIGHT_IMAGE]),
  1640.                                                         GA_RelRight,    -(SizeWidth - 1 + ArrowWidth),
  1641.                                                         GA_RelBottom,    -(SizeHeight - 1),
  1642.                                                         GA_Height,    SizeHeight,
  1643.                                                         GA_Width,    ArrowWidth,
  1644.                                                         GA_Immediate,    TRUE,
  1645.                                                         GA_RelVerify,    TRUE,
  1646.                                                         GA_BottomBorder,TRUE,
  1647.  
  1648.                                                         ICA_TARGET,    ICTARGET_IDCMP,
  1649.                                                         ICA_MAP,    (ULONG)ArrowMappings,
  1650.                                                         TAG_DONE);
  1651.                                                     if(xdev -> gadget[RIGHT_ARROW])
  1652.                                                         Result = TRUE;
  1653.                                                 }
  1654.                                             }
  1655.                                         }
  1656.                                     }
  1657.                                 }
  1658.                             }
  1659.                         }
  1660.                     }
  1661.                 }
  1662.  
  1663.                 FreeScreenDrawInfo(Screen,DrawInfo);
  1664.             }
  1665.         }
  1666.     }
  1667.  
  1668.     return(Result);
  1669. }
  1670.  
  1671.     /* WindowResize(gx_device *dev):
  1672.      *
  1673.      *    Update the slider sizes and positions after the window
  1674.      *    was resized.
  1675.      */
  1676.  
  1677. private VOID
  1678. WindowResize(gx_device *dev)
  1679. {
  1680.     LONG    DeltaX,
  1681.         DeltaY,
  1682.         Temp;
  1683.  
  1684.         /* Query the current horizontal slider position. */
  1685.  
  1686.     if((Temp = LAYERXOFFSET(xdev -> window) + xdev -> window -> GZZWidth) > xdev -> width)
  1687.         DeltaX = xdev -> width - Temp;
  1688.     else
  1689.         DeltaX = 0;
  1690.  
  1691.         /* Query the current vertical slider position. */
  1692.  
  1693.     if((Temp = LAYERYOFFSET(xdev -> window) + xdev -> window -> GZZHeight) > xdev -> height)
  1694.         DeltaY = xdev -> height - Temp;
  1695.     else
  1696.         DeltaY = 0;
  1697.  
  1698.         /* Move the currently displayed window area around. */
  1699.  
  1700.     if(DeltaX || DeltaY)
  1701.         ScrollLayer(NULL,xdev -> window -> RPort -> Layer,DeltaX,DeltaY);
  1702.  
  1703.         /* Update the new horizontal slider position and size. */
  1704.  
  1705.     SetGadgetAttrs(xdev -> gadget[HORIZONTAL_SCROLLER],xdev -> window,NULL,
  1706.         PGA_Top,    LAYERXOFFSET(xdev -> window),
  1707.         PGA_Visible,    xdev -> window -> GZZWidth,
  1708.         PGA_Total,    xdev -> width,
  1709.     TAG_DONE);
  1710.  
  1711.         /* Update the new vertical slider position and size. */
  1712.  
  1713.     SetGadgetAttrs(xdev -> gadget[VERTICAL_SCROLLER],xdev -> window,NULL,
  1714.         PGA_Top,    LAYERYOFFSET(xdev -> window),
  1715.         PGA_Visible,    xdev -> window -> GZZHeight,
  1716.         PGA_Total,    xdev -> height,
  1717.     TAG_DONE);
  1718. }
  1719.  
  1720.     /* WindowUpdate(struct Gadget *Gadget,gx_device *dev):
  1721.      *
  1722.      *    Move the currently visible portion of the
  1723.      *    window according to the current slider
  1724.      *    position.
  1725.      */
  1726.  
  1727. private VOID
  1728. WindowUpdate(struct Gadget *Gadget,gx_device *dev)
  1729. {
  1730.     LONG Storage;
  1731.  
  1732.     switch(Gadget -> GadgetID)
  1733.     {
  1734.         case HORIZONTAL_SCROLLER:
  1735.  
  1736.             if(GetAttr(PGA_Top,Gadget,&Storage))
  1737.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  1738.  
  1739.             break;
  1740.  
  1741.         case VERTICAL_SCROLLER:
  1742.  
  1743.             if(GetAttr(PGA_Top,Gadget,&Storage))
  1744.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  1745.  
  1746.             break;
  1747.     }
  1748. }
  1749.  
  1750.     /* MoveAround(struct Gadget *Gadget,int How,gx_device *dev):
  1751.      *
  1752.      *    Move the currently visible window area according to
  1753.      *    user input.
  1754.      */
  1755.  
  1756. private VOID
  1757. MoveAround(struct Gadget *Gadget,LONG How,gx_device *dev)
  1758. {
  1759.     LONG Storage;
  1760.  
  1761.     if(GetAttr(PGA_Top,Gadget,&Storage))
  1762.     {
  1763.         LONG Max = 0;
  1764.  
  1765.         switch(Gadget -> GadgetID)
  1766.         {
  1767.             case HORIZONTAL_SCROLLER:
  1768.  
  1769.                 Max = xdev -> width - xdev -> window -> GZZWidth;
  1770.                 break;
  1771.  
  1772.             case VERTICAL_SCROLLER:
  1773.  
  1774.                 Max = xdev -> height - xdev -> window -> GZZHeight;
  1775.                 break;
  1776.         }
  1777.  
  1778.         switch(How)
  1779.         {
  1780.             case MOVE_MIN:
  1781.  
  1782.                 Storage = 0;
  1783.                 break;
  1784.  
  1785.             case MOVE_MAX:
  1786.  
  1787.                 Storage = Max;
  1788.                 break;
  1789.  
  1790.             case MOVE_DOWN:
  1791.  
  1792.                 if(Storage > xdev -> height / 100)
  1793.                     Storage -= xdev -> height / 100;
  1794.                 else
  1795.                     Storage = 0;
  1796.  
  1797.                 break;
  1798.  
  1799.             case MOVE_FAR_DOWN:
  1800.  
  1801.                 if(Storage > xdev -> height / 10)
  1802.                     Storage -= xdev -> height / 10;
  1803.                 else
  1804.                     Storage = 0;
  1805.  
  1806.                 break;
  1807.  
  1808.             case MOVE_FAR_UP:
  1809.  
  1810.                 if(Storage + xdev -> width / 10 < Max)
  1811.                     Storage += xdev -> width / 10;
  1812.                 else
  1813.                     Storage = Max;
  1814.  
  1815.                 break;
  1816.  
  1817.             case MOVE_UP:
  1818.  
  1819.                 if(Storage + xdev -> width / 100 < Max)
  1820.                     Storage += xdev -> width / 100;
  1821.                 else
  1822.                     Storage = Max;
  1823.  
  1824.                 break;
  1825.         }
  1826.  
  1827.         switch(Gadget -> GadgetID)
  1828.         {
  1829.             case HORIZONTAL_SCROLLER:
  1830.  
  1831.                 if(LAYERXOFFSET(xdev -> window) != Storage)
  1832.                 {
  1833.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  1834.  
  1835.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  1836.                         PGA_Top,Storage,
  1837.                     TAG_DONE);
  1838.                 }
  1839.  
  1840.                 break;
  1841.  
  1842.             case VERTICAL_SCROLLER:
  1843.  
  1844.                 if(LAYERYOFFSET(xdev -> window) != Storage)
  1845.                 {
  1846.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  1847.  
  1848.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  1849.                         PGA_Top,Storage,
  1850.                     TAG_DONE);
  1851.                 }
  1852.  
  1853.                 break;
  1854.         }
  1855.     }
  1856. }
  1857.  
  1858.     /* DispatchSuperWindow(gx_device *dev):
  1859.      *
  1860.      *    Dispatch user window input.
  1861.      */
  1862.  
  1863. private VOID
  1864. DispatchSuperWindow(gx_device *dev)
  1865. {
  1866.     STATIC struct Gadget    *CurrentGadget = NULL;
  1867.  
  1868.     struct IntuiMessage    *IntuiMessage;
  1869.     ULONG             MsgClass,
  1870.                  MsgCode,
  1871.                  MsgQualifier;
  1872.     struct Gadget        *MsgGadget;
  1873.  
  1874.     while(NULL != (IntuiMessage = (struct IntuiMessage *)GetMsg(
  1875.         xdev -> window -> UserPort)))
  1876.     {
  1877.         MsgClass    = IntuiMessage -> Class;
  1878.         MsgCode        = IntuiMessage -> Code;
  1879.         MsgQualifier    = IntuiMessage -> Qualifier;
  1880.         MsgGadget    = IntuiMessage -> IAddress;
  1881.  
  1882.         ReplyMsg((struct Message *)IntuiMessage);
  1883.  
  1884.         switch(MsgClass)
  1885.         {
  1886.             case IDCMP_VANILLAKEY:
  1887.  
  1888.                 if(MsgCode == '\033' || MsgCode == '\003')
  1889.                     Signal((struct Task *)xdev -> main,SIG_KILL);
  1890.  
  1891.                 break;
  1892.  
  1893.             case IDCMP_RAWKEY:
  1894.  
  1895.                 switch(MsgCode)
  1896.                 {
  1897.                     case HELP_CODE:
  1898.  
  1899.                         DisplayBeep(xdev -> window -> WScreen);
  1900.  
  1901.                         break;
  1902.  
  1903.                     case CURSORUP:
  1904.  
  1905.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  1906.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MIN,dev);
  1907.                         else
  1908.                         {
  1909.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1910.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_DOWN,dev);
  1911.                             else
  1912.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  1913.                         }
  1914.  
  1915.                         break;
  1916.  
  1917.                     case CURSORLEFT:
  1918.  
  1919.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  1920.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MIN,dev);
  1921.                         else
  1922.                         {
  1923.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1924.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_DOWN,dev);
  1925.                             else
  1926.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  1927.                         }
  1928.  
  1929.                         break;
  1930.  
  1931.                     case CURSORRIGHT:
  1932.  
  1933.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  1934.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MAX,dev);
  1935.                         else
  1936.                         {
  1937.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1938.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_UP,dev);
  1939.                             else
  1940.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  1941.                         }
  1942.  
  1943.                         break;
  1944.  
  1945.                     case CURSORDOWN:
  1946.  
  1947.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  1948.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MAX,dev);
  1949.                         else
  1950.                         {
  1951.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1952.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_UP,dev);
  1953.                             else
  1954.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  1955.                         }
  1956.  
  1957.                         break;
  1958.  
  1959.                     default:
  1960.  
  1961.                         break;
  1962.                 }
  1963.  
  1964.                 break;
  1965.  
  1966.             case IDCMP_CLOSEWINDOW:
  1967.  
  1968.                 Signal((struct Task *)xdev -> main,SIG_KILL);
  1969.  
  1970.                 break;
  1971.  
  1972.             case IDCMP_GADGETDOWN:
  1973.  
  1974.                 CurrentGadget = MsgGadget;
  1975.  
  1976.                 WindowUpdate(MsgGadget,dev);
  1977.  
  1978.                 break;
  1979.  
  1980.             case IDCMP_GADGETUP:
  1981.  
  1982.                 CurrentGadget = NULL;
  1983.  
  1984.                 WindowUpdate(MsgGadget,dev);
  1985.  
  1986.                 break;
  1987.  
  1988.             case IDCMP_MOUSEMOVE:
  1989.  
  1990.                 if(CurrentGadget)
  1991.                     WindowUpdate(CurrentGadget,dev);
  1992.  
  1993.                 break;
  1994.  
  1995.             case IDCMP_IDCMPUPDATE:
  1996.  
  1997.                 switch(GetTagData(GA_ID,0,(struct TagItem *)MsgGadget))
  1998.                 {
  1999.                     case UP_ARROW:
  2000.  
  2001.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  2002.                         break;
  2003.  
  2004.                     case DOWN_ARROW:
  2005.  
  2006.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  2007.                         break;
  2008.  
  2009.                     case LEFT_ARROW:
  2010.  
  2011.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  2012.                         break;
  2013.  
  2014.                     case RIGHT_ARROW:
  2015.  
  2016.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  2017.                         break;
  2018.  
  2019.                     default:
  2020.  
  2021.                         break;
  2022.                 }
  2023.  
  2024.                 break;
  2025.  
  2026.             case IDCMP_NEWSIZE:
  2027.  
  2028.                 WindowResize(dev);
  2029.  
  2030.                 break;
  2031.  
  2032.             default:
  2033.  
  2034.                 break;
  2035.         }
  2036.     }
  2037. }
  2038.  
  2039.     /* PrintPrinterError(const char *header, LONG io_Error):
  2040.      *
  2041.      *    Print a real error message for Printer.device errors.
  2042.      */
  2043.  
  2044. private VOID
  2045. PrintPrinterError(const char *header, LONG io_Error)
  2046. {
  2047.     char buffer[256];
  2048.     char defaultmessage[64];
  2049.     const char *errormessage;
  2050.                     
  2051.     switch (io_Error)
  2052.     {
  2053.         case PDERR_CANCEL:
  2054.             errormessage = "user cancelled print";
  2055.             break;
  2056.         case PDERR_NOTGRAPHICS:
  2057.             errormessage = "printer cannot output graphics";
  2058.             break;
  2059.         case PDERR_BADDIMENSION:
  2060.             errormessage = "print dimensions illegal";
  2061.             break;
  2062.         case PDERR_INTERNALMEMORY:
  2063.             errormessage = "no memory for internal variables";
  2064.             break;
  2065.         case PDERR_BUFFERMEMORY:
  2066.             errormessage = "no memory for print buffer";
  2067.             break;
  2068.         case IOERR_OPENFAIL:
  2069.             errormessage = "device/unit failed to open";
  2070.             break;
  2071.         case IOERR_ABORTED:
  2072.             errormessage = "request terminated early [after AbortIO()]";
  2073.             break;
  2074.         case IOERR_NOCMD:
  2075.             errormessage = "command not supported by device";
  2076.             break;
  2077.         case IOERR_BADLENGTH:
  2078.             errormessage = "not a valid length (usually IO_LENGTH)";
  2079.             break;
  2080.         case IOERR_BADADDRESS:
  2081.             errormessage = "invalid address (misaligned or bad range)";
  2082.             break;
  2083.         case IOERR_UNITBUSY:
  2084.             errormessage = "device opens ok, but requested unit is busy";
  2085.             break;
  2086.         case IOERR_SELFTEST:
  2087.             errormessage = "hardware failed self-test";
  2088.             break;
  2089.         default:
  2090.             sprintf(defaultmessage, "unknown I/O error #%ld", io_Error);
  2091.             errormessage = defaultmessage;
  2092.             break;
  2093.     }
  2094.     sprintf(buffer, "%s (%s)\n", header, errormessage);
  2095.     eprintf(buffer);
  2096. }
  2097.  
  2098.     /* Simple routine to call the cleanup routine of a device,
  2099.      * all devices are smart enough to handle shutdown in
  2100.      * case they have not been opened yet.
  2101.      */
  2102.  
  2103. private void 
  2104. close_device(gx_device_amiga *dev)
  2105. {
  2106.     if(xdev -> std_procs . close_device)
  2107.         (*xdev -> std_procs . close_device)((gx_device *)dev);
  2108. }
  2109.  
  2110.     /* devcleanup():
  2111.      *
  2112.      *    Clean up all devices, free all resources.
  2113.      */
  2114.  
  2115. void
  2116. devcleanup()
  2117. {
  2118.     close_device(&gs_amiga_device);
  2119.     close_device(&gs_amiga_custom_device);
  2120.     close_device(&gs_amiga_printer_device);
  2121.     close_device(&gs_amiga_ilbm_device);
  2122. }
  2123.  
  2124.     /* amiga_set_pen(gx_device *dev,gx_color_index color):
  2125.      *
  2126.      *    Sets the rendering pen and remembers the current
  2127.      *    settings.
  2128.      */
  2129.  
  2130. private VOID
  2131. amiga_set_pen(gx_device *dev,gx_color_index color)
  2132. {
  2133.     if(xdev -> last_pen != color)
  2134.         SetAPen(xdev -> rport,xdev -> last_pen = color);
  2135. }
  2136.  
  2137.     /* amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  2138.      *
  2139.      *    Map a colour either to the black or the light rendering pen.
  2140.      */
  2141.  
  2142. private gx_color_index
  2143. amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  2144. {
  2145.     if((red | green | blue) > gx_max_color_value / 2)
  2146.         return(LightPen);
  2147.     else
  2148.         return(DarkPen);
  2149. }
  2150.  
  2151.     /* amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  2152.      *
  2153.      *    Map the light/dark rendering pen to RGB values.
  2154.      */
  2155.  
  2156. private int
  2157. amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  2158. {
  2159.     int i;
  2160.  
  2161.     if(color == LightPen)
  2162.     {
  2163.         for(i = 0 ; i < 3 ; i++)
  2164.             rgb[i] = gx_max_color_value;
  2165.     }
  2166.     else
  2167.     {
  2168.         for(i = 0 ; i < 3 ; i++)
  2169.             rgb[i] = 0;
  2170.     }
  2171.  
  2172.     return(0);
  2173. }
  2174.  
  2175.     /* AllocatePens(struct ViewPort *VPort,LONG CubeSize):
  2176.      *
  2177.      *    Allocate shareable viewport pens.
  2178.      */
  2179.  
  2180. private LONG *
  2181. AllocatePens(struct ViewPort *VPort,LONG CubeSize)
  2182. {
  2183.     if(GfxBase -> LibNode . lib_Version >= 39)
  2184.     {
  2185.         LONG Total = CubeSize * CubeSize * CubeSize,*Pens;
  2186.  
  2187.         Pens = (LONG *)AllocVec(sizeof(LONG) * Total, MEMF_ANY);
  2188.         if(Pens)
  2189.         {
  2190.             LONG i,r,g,b,max = CubeSize - 1;
  2191.  
  2192.             for(i = 0 ; i < Total ; i++)
  2193.                 Pens[i] = -1;
  2194.  
  2195.             i = 0;
  2196.  
  2197.             for(r = 0 ; r < CubeSize ; r++)
  2198.             {
  2199.                 for(g = 0 ; g < CubeSize ; g++)
  2200.                 {
  2201.                     for(b = 0 ; b < CubeSize ; b++)
  2202.                     {
  2203.                         if((Pens[i++] = ObtainBestPen(VPort -> ColorMap,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max),
  2204.                             OBP_FailIfBad,    TRUE,
  2205.                             OBP_Precision,    PRECISION_IMAGE,
  2206.                         TAG_DONE)) == -1)
  2207.                         {
  2208.                             FreeVec(Pens);
  2209.  
  2210.                             return(NULL);
  2211.                         }
  2212.                     }
  2213.                 }
  2214.             }
  2215.  
  2216.             return(Pens);
  2217.         }
  2218.     }
  2219.  
  2220.     return(NULL);
  2221. }
  2222.  
  2223.     /* amiga_open_default(gx_device *dev):
  2224.      *
  2225.      *    Open the default device, i.e. a window on the Workbench screen.
  2226.      */
  2227.  
  2228. private int
  2229. amiga_open_default(gx_device *dev)
  2230. {
  2231.     struct Screen *DefaultScreen;
  2232.  
  2233.         /* Get a lock on the default public screen. */
  2234.  
  2235.     DefaultScreen = LockPubScreen(NULL);
  2236.     if(DefaultScreen)
  2237.     {
  2238.         struct DisplayInfo    DisplayInfo;
  2239.         ULONG             Mode;
  2240.  
  2241.             /* Get the default public screen display mode. */
  2242.  
  2243.         Mode = GetVPModeID(&DefaultScreen -> ViewPort);
  2244.  
  2245.             /* Inquire display mode information. */
  2246.  
  2247.         if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode))
  2248.         {
  2249.             LONG    ScreenWidth,
  2250.                 ScreenHeight;
  2251.             LONG    i;
  2252.             LONG    Depth;
  2253.  
  2254.             if(GfxBase -> LibNode . lib_Version >= 39)
  2255.                 Depth = GetBitMapAttr(DefaultScreen -> RastPort . BitMap,BMA_DEPTH);
  2256.             else
  2257.                 Depth = DefaultScreen -> RastPort . BitMap -> Depth;
  2258.  
  2259.                 /* Determine screen view dimensions. */
  2260.  
  2261.             if(DefaultScreen -> ViewPort . ColorMap -> cm_vpe)
  2262.             {
  2263.                 struct ViewPortExtra *Extra = DefaultScreen -> ViewPort . ColorMap -> cm_vpe;
  2264.  
  2265.                 ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2266.                 ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2267.             }
  2268.             else
  2269.             {
  2270.                 struct ViewPortExtra *Extra;
  2271.  
  2272.                 Extra = (struct ViewPortExtra *)GfxLookUp(
  2273.                     &DefaultScreen -> ViewPort);
  2274.                 if(Extra)
  2275.                 {
  2276.                     ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2277.                     ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2278.                 }
  2279.                 else
  2280.                 {
  2281.                     ScreenWidth    = DefaultScreen -> Width;
  2282.                     ScreenHeight    = DefaultScreen -> Height;
  2283.                 }
  2284.             }
  2285.  
  2286.                 /* Adjust device to screen resolution. */
  2287.  
  2288.             if (!ResolutionSwitch)    /* Has user set -r at command line? */
  2289.             {    /* no */
  2290.  
  2291.                 /* Compute the dots_per_inch resolution from the 
  2292.                  * ticks_per_pixel resolution in the display database.
  2293.                  * See #define MAGIC_... for a comment.
  2294.                  */
  2295.  
  2296.                 if (DisplayInfo.Resolution.x && DisplayInfo.Resolution.y)
  2297.                 {
  2298.                     dev->x_pixels_per_inch = MAGIC_DPI_BASE_VALUE 
  2299.                         / DisplayInfo.Resolution.x;
  2300.                     dev->y_pixels_per_inch = MAGIC_DPI_BASE_VALUE 
  2301.                         / DisplayInfo.Resolution.y;
  2302.  
  2303.                     if (GeometrySwitch)    /* Has user set -g at command line? */
  2304.                     {    /* yes => update MediaSize to remain consistent */
  2305.                         gx_device_set_width_height(dev, dev->width, 
  2306.                             dev->height);
  2307.                     }
  2308.                     else
  2309.                     {    /* no => update width/height to remain consistent */
  2310.                         gx_device_set_media_size(dev, dev->MediaSize[0], 
  2311.                             dev->MediaSize[1]);
  2312.                     }
  2313.                 }
  2314.             }
  2315.  
  2316.                 /* Allocate a bitmap ready to be used for
  2317.                  * rendering.
  2318.                  */
  2319.  
  2320.             xdev -> super_bitmap = CreateBitMap(xdev -> width, 
  2321.                 xdev -> height, Depth, BMF_DISPLAYABLE, 
  2322.                 DefaultScreen -> RastPort . BitMap, FALSE);
  2323.             if(xdev -> super_bitmap)
  2324.             {
  2325.                     /* Clear the bitplanes. */
  2326.  
  2327.                 BltBitMap(xdev -> super_bitmap,0,0,xdev -> super_bitmap,0,0,xdev -> width,xdev -> height,0x00,(1 << xdev -> super_bitmap -> Depth) - 1,NULL);
  2328.  
  2329.                     /* Create the scroller handles. */
  2330.  
  2331.                 if(CreateScrollers(dev,DefaultScreen))
  2332.                 {
  2333.                     struct IBox ZoomBox;
  2334.  
  2335.                         /* Set up the window alternate
  2336.                          * position.
  2337.                          */
  2338.  
  2339.                     ZoomBox . Left        = 0;
  2340.                     ZoomBox . Top        = DefaultScreen -> BarHeight + 1;
  2341.                     ZoomBox . Width        = ScreenWidth;
  2342.                     ZoomBox . Height    = ScreenHeight - ZoomBox . Top;
  2343.  
  2344.                         /* Eventually, open the display window. */
  2345.  
  2346.                     xdev -> window = OpenWindowTags(NULL,
  2347.                         WA_InnerWidth,        MIN(DefaultScreen->Width / 2, 
  2348.                             xdev -> width),
  2349.                         WA_InnerHeight,        MIN(DefaultScreen->Height / 2, 
  2350.                             xdev -> height),
  2351.                         WA_CloseGadget,        TRUE,
  2352.                         WA_DepthGadget,        TRUE,
  2353.                         WA_SizeGadget,        TRUE,
  2354.                         WA_SizeBRight,        TRUE,
  2355.                         WA_SizeBBottom,        TRUE,
  2356.                         WA_Zoom,        (ULONG)(&ZoomBox),
  2357.                         WA_DragBar,        TRUE,
  2358.                         WA_NoCareRefresh,    TRUE,
  2359.                         WA_GimmeZeroZero,    TRUE,
  2360.                         WA_RMBTrap,        TRUE,
  2361.                         WA_SuperBitMap,        (ULONG)(xdev->super_bitmap),
  2362.                         WA_Gadgets,    (ULONG)(xdev->gadget[VERTICAL_SCROLLER]),
  2363.                         WA_CustomScreen,    (ULONG)DefaultScreen,
  2364.                         WA_Title,    (ULONG)"Ghostscript Amiga output window",
  2365.                         TAG_DONE);
  2366.                     if(xdev -> window)
  2367.                     {
  2368.                         xdev -> temp_rport = CreateTempRPort(
  2369.                             xdev -> window -> RPort);
  2370.                         if(xdev -> temp_rport)
  2371.                         {
  2372.                             xdev -> temp_array = (UBYTE *)AllocVec(
  2373.                                 (xdev -> window -> WScreen -> Width + 15) & ~15, 
  2374.                                 MEMF_ANY);
  2375.                             if(xdev -> temp_array)
  2376.                             {
  2377.                                 const sigset_t trapped = sigmask(SIGINT);
  2378.                                 struct Task *Task;
  2379.                                 long TaskPri;
  2380.  
  2381.                                     /* Don't let anybody interrupt us! */
  2382. #ifdef IXEMUL
  2383.                                 sigprocmask(SIG_BLOCK,&trapped,NULL);
  2384. #endif
  2385.                                     /* Who's calling? */
  2386.  
  2387.                                 xdev -> main = (struct Process *)FindTask(NULL);
  2388.                                 
  2389.                                     /* Bring the window dispatcher task
  2390.                                      * to life with +1 priority...
  2391.                                      */
  2392.  
  2393.                                 Forbid();
  2394.  
  2395.                                 TaskPri = 1 + 
  2396.                                     xdev->main->pr_Task.tc_Node.ln_Pri;
  2397.                                 if (127 < TaskPri)    /* Ouch... */
  2398.                                     TaskPri = 127;    /* ;-) */
  2399.                                 
  2400.                                 Task = CreateTask(
  2401.                                     "Ghostscript window dispatcher", 
  2402.                                     TaskPri, DispatchTask, 8192);
  2403.                                 if(Task)
  2404.                                 {
  2405.                                         /* Cheap... */
  2406.  
  2407.                                     Task -> tc_UserData = dev;
  2408.  
  2409.                                         /* Clear the handshake bit. */
  2410.  
  2411.                                     SetSignal(0,SIG_HANDSHAKE);
  2412.  
  2413.                                         /* Wake it up. */
  2414.  
  2415.                                     Signal(Task,SIG_HANDSHAKE);
  2416.  
  2417.                                         /* Wake the task up. */
  2418.  
  2419.                                     Signal(Task,SIG_WAKEUP);
  2420.  
  2421.                                         /* Wait for the report. */
  2422.  
  2423.                                     Wait(SIG_HANDSHAKE);
  2424.  
  2425.                                         /* Get the result. */
  2426.  
  2427.                                     Task = xdev -> dispatcher;
  2428.                                 }
  2429.  
  2430.                                 Permit();
  2431.  
  2432.                                     /* Unblock signals. */
  2433. #ifdef IXEMUL
  2434.                                 sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2435. #endif
  2436.                                     /* Did we succeed in creating
  2437.                                      * the dispatcher task?
  2438.                                      */
  2439.  
  2440.                                 if(Task)
  2441.                                 {
  2442.                                     UWORD    MaxValue = 0,
  2443.                                         MinValue = 15000,
  2444.                                         Value,
  2445.                                         R,G,B;
  2446.  
  2447.                                         /* Set the window limits. */
  2448.  
  2449.                                     WindowLimits(xdev -> window,xdev -> window -> BorderLeft + MINIMUM_WIDTH + xdev -> window -> BorderRight,xdev -> window -> BorderTop + MINIMUM_HEIGHT + xdev -> window -> BorderBottom,xdev -> window -> BorderLeft + xdev -> width + xdev -> window -> BorderRight,xdev -> window -> BorderTop + xdev -> height + xdev -> window -> BorderBottom);
  2450.  
  2451.                                         /* Update the sliders. */
  2452.  
  2453.                                     WindowResize(dev);
  2454.  
  2455.                                         /* Look for the darkest and the lightest screen colours. */
  2456.  
  2457.                                     for(i = 0 ; i < MIN(xdev -> window -> WScreen -> ViewPort . ColorMap -> Count,(1 << Depth)) ; i++)
  2458.                                     {
  2459.                                         Value = GetRGB4(xdev -> window -> WScreen -> ViewPort . ColorMap,i);
  2460.  
  2461.                                         R = (Value >> 8) & 0xF;
  2462.                                         G = (Value >> 4) & 0xF;
  2463.                                         B =  Value       & 0xF;
  2464.  
  2465.                                             /* Luminance conversion included */
  2466.  
  2467.                                         Value = R * 299 + G * 588 + B * 113;
  2468.  
  2469.                                         if(Value > MaxValue)
  2470.                                         {
  2471.                                             MaxValue = Value;
  2472.  
  2473.                                             LightPen = i;
  2474.                                         }
  2475.  
  2476.                                         if(Value < MinValue)
  2477.                                         {
  2478.                                             MinValue = Value;
  2479.  
  2480.                                             DarkPen = i;
  2481.                                         }
  2482.                                     }
  2483.  
  2484.                                         /* Fill in the rest. */
  2485.  
  2486.                                     xdev -> rport    = xdev -> window -> RPort;
  2487.  
  2488.                                         /* Does the display support
  2489.                                          * at least eight colours?
  2490.                                          */
  2491.  
  2492.                                     if(Depth >= 3)
  2493.                                     {
  2494.                                         LONG cube_size,max;
  2495.  
  2496.                                             /* Set up a fitting colour cube. */
  2497.  
  2498.                                         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  2499.                                         {
  2500.                                             if((max = cube_size * cube_size * cube_size) <= 1 << Depth)
  2501.                                                 break;
  2502.                                         }
  2503.  
  2504.                                             /* Got enough colours? */
  2505.  
  2506.                                         if(cube_size != 1)
  2507.                                         {
  2508.                                             LONG *Pens;
  2509.  
  2510.                                                 /* Try to grab the cube colours,
  2511.                                                  * making a colour display.
  2512.                                                  */
  2513.  
  2514.                                             Pens = AllocatePens(&xdev -> window -> WScreen -> ViewPort,cube_size);
  2515.                                             if(Pens)
  2516.                                                 set_colour_device((gx_device_amiga *)dev,cube_size,Pens);
  2517.                                         }
  2518.                                     }
  2519.  
  2520.                                     SetBPen(xdev -> rport,0);
  2521.                                     SetDrMd(xdev -> rport,JAM2);
  2522.  
  2523.                                     amiga_set_pen(dev,DarkPen);
  2524.  
  2525.                                     UnlockPubScreen(NULL,DefaultScreen);
  2526.  
  2527.                                     return(0);
  2528.                                 }
  2529.                                 else
  2530.                                     eprintf("Ghostscript: failed to create dispatcher task\n");
  2531.                             }
  2532.                             else
  2533.                                 eprintf("Ghostscript: failed to create temporary line buffer\n");
  2534.                         }
  2535.                         else
  2536.                             eprintf("Ghostscript: failed to create temporary raster port\n");
  2537.                     }
  2538.                     else
  2539.                         eprintf("Ghostscript: failed to open window\n");
  2540.                 }
  2541.                 else
  2542.                     eprintf("Ghostscript: failed to allocate scrollers\n");
  2543.             }
  2544.             else
  2545.                 eprintf("Ghostscript: failed to allocate bitmap\n");
  2546.         }
  2547.         else
  2548.             eprintf("Ghostscript: failed to get display mode information\n");
  2549.  
  2550.         UnlockPubScreen(NULL,DefaultScreen);
  2551.     }
  2552.     else
  2553.         eprintf("Ghostscript: failed to lock default public screen\n");
  2554.  
  2555.     return_error(gs_error_unknownerror);
  2556. }
  2557.  
  2558. private int
  2559. amiga_open_custom(gx_device *dev)
  2560. {
  2561.     UBYTE    Buffer[DISPLAYNAMELEN + 1] = "";    /* see graphics/displayinfo.h */
  2562.     ULONG    ScreenID    = INVALID_ID;
  2563.     BOOL    DontTouch    = FALSE;
  2564.  
  2565.         /* Has user supplied the ID of a Display Mode? */
  2566.  
  2567.     if (1 == sscanf(xdev->display_mode, "0x%lx", &ScreenID)
  2568.         || 1 == sscanf(xdev->display_mode, "0X%lx", &ScreenID))
  2569.     {    /* yes => check wether it is available */
  2570.  
  2571.         if (ModeNotAvailable(ScreenID))
  2572.         {
  2573.             ScreenID = INVALID_ID;
  2574.         }
  2575.         else
  2576.         {
  2577.             DontTouch = TRUE;    /* Don't overwrite the env. variable. */
  2578.         }
  2579.     }
  2580.     else
  2581.     {    /* no */
  2582.  
  2583.             /* Has user supplied the name of a Display Mode? */
  2584.  
  2585.         if ('\0' != xdev->display_mode[0])
  2586.         {    /* yes */
  2587.  
  2588.             strcpy(Buffer, xdev->display_mode);
  2589.         }
  2590.         else
  2591.         {    /* no => try to read it from the environment variable */
  2592.  
  2593.             GetVar("GS_DISPLAYMODE", Buffer, sizeof (Buffer), NULL);
  2594.         }
  2595.  
  2596.         if ('\0' != Buffer[0])
  2597.         {
  2598.             UBYTE PatternBuffer[(sizeof (Buffer) * 2) + 2];
  2599.     
  2600.                 /* Set up the search pattern. */
  2601.     
  2602.             if (0 <= ParsePatternNoCase(Buffer, PatternBuffer, 
  2603.                 sizeof (PatternBuffer)))
  2604.             {
  2605.                 ULONG CurrentID = INVALID_ID;
  2606.     
  2607.                     /* Scan the entire list. */
  2608.     
  2609.                 while (INVALID_ID != (CurrentID = NextDisplayInfo(CurrentID)))
  2610.                 {
  2611.                     struct NameInfo    NameInfo;
  2612.     
  2613.                         /* Is this mode available? */
  2614.     
  2615.                     if (ModeNotAvailable(CurrentID))
  2616.                     {    /* no => continue loop */
  2617.                         continue;
  2618.                     }
  2619.     
  2620.                         /* Get the name information. */
  2621.     
  2622.                     if (GetDisplayInfoData(NULL, (UBYTE *)&NameInfo, 
  2623.                         sizeof (struct NameInfo), DTAG_NAME, CurrentID))
  2624.                     {
  2625.                             /* Does the mode name match the pattern given? */
  2626.                         if (MatchPatternNoCase(PatternBuffer, NameInfo.Name))
  2627.                         {
  2628.                             ScreenID = CurrentID;
  2629.     
  2630.                                 /* Don't overwrite the env. variable. */
  2631.     
  2632.                             DontTouch = TRUE;
  2633.                             break;
  2634.                         }
  2635.                     }
  2636.                 }
  2637.             }
  2638.         }
  2639.     }
  2640.  
  2641.     if (INVALID_ID == ScreenID && AslBase)
  2642.     {
  2643.         struct ScreenModeRequester *ScreenModeRequester;
  2644.  
  2645.         ScreenModeRequester = (struct ScreenModeRequester *)
  2646.             AllocAslRequestTags(ASL_ScreenModeRequest, TAG_DONE);
  2647.         if (ScreenModeRequester)
  2648.         {
  2649.             if (AslRequestTags(ScreenModeRequester,
  2650.                 ASLSM_TitleText,    (ULONG)"Select Ghostscript Display Mode",
  2651.                 ASLSM_MinDepth,        1,
  2652.                 ASLSM_MaxDepth,        8,
  2653.                 TAG_DONE))
  2654.             {
  2655.                 ScreenID = ScreenModeRequester->sm_DisplayID;
  2656.                 FreeAslRequest(ScreenModeRequester);
  2657.             }
  2658.             else
  2659.             {
  2660.                     /* Check wether any error occured (V38 only) */
  2661.                 
  2662.                 if (38 <= AslBase->lib_Version)
  2663.                 {
  2664.                     if (0 != IoErr())
  2665.                     {    /* yes => print additional error message */
  2666.                         eprintf("Ghostscript: failed to display screenmode "
  2667.                             "requester\n");
  2668.                     }
  2669.                 }
  2670.                  
  2671.                 /* User cancelled or IoErr() => fall back to default */
  2672.  
  2673.                 FreeAslRequest(ScreenModeRequester);
  2674.                 return (amiga_open_default(dev));
  2675.             }
  2676.         }
  2677.     }
  2678.  
  2679.         /* Is selected mode available? */
  2680.  
  2681.     if (ModeNotAvailable(ScreenID))
  2682.     {    /* no => fall back to default */
  2683.         return (amiga_open_default(dev));
  2684.     }
  2685.     else
  2686.     {    /* yes => try to open the screen */
  2687.         int result = amiga_open(dev, ScreenID);
  2688.  
  2689.             /* If successful store the name of the
  2690.              * screen mode selected.
  2691.              */
  2692.  
  2693.         if(!result && !DontTouch)
  2694.         {
  2695.             struct NameInfo    NameInfo;
  2696.  
  2697.             if (GetDisplayInfoData(NULL, (UBYTE *)&NameInfo, 
  2698.                 sizeof (struct NameInfo), DTAG_NAME, ScreenID))
  2699.             {
  2700.                 SetVar("GS_DISPLAYMODE", NameInfo.Name, -1, NULL);
  2701.             }
  2702.         }
  2703.  
  2704.         return (result);
  2705.     }
  2706. }
  2707.  
  2708.     /* amiga_open_printer(gx_device *dev):
  2709.      *
  2710.      *    Open the printer device.
  2711.      */
  2712.  
  2713. private int
  2714. amiga_open_printer(gx_device *dev)
  2715. {
  2716.     xdev->port = CreateMsgPort();
  2717.     if (xdev->port)
  2718.     {
  2719.         xdev->printer = (struct IODRPReq *)CreateIORequest(xdev->port, 
  2720.             sizeof(struct IODRPReq));
  2721.         if (xdev->printer)
  2722.         {
  2723.             if (!OpenDevice("printer.device", 0, 
  2724.                 (struct IORequest *)xdev->printer, 0))
  2725.             {
  2726.                 struct PrinterData *PD;
  2727.                 struct PrinterExtendedData *PED;
  2728.                 struct Preferences *Prefs;
  2729.  
  2730.                     /* Get the printer internal data. */
  2731.                     
  2732.                 PD = (struct PrinterData *)xdev->printer->io_Device;
  2733.                 PED    = &PD->pd_SegmentData->ps_PED;
  2734.                 Prefs = &PD->pd_Preferences;
  2735.  
  2736.                     /* Adjust device to current printer resolution. */
  2737.  
  2738.                 if (!ResolutionSwitch)    /* Has user set -r at command line? */
  2739.                 {    /* no */
  2740.                     dev->x_pixels_per_inch = (float)PED->ped_XDotsInch;
  2741.                     dev->y_pixels_per_inch = (float)PED->ped_YDotsInch;
  2742.         
  2743.                     if (GeometrySwitch)    /* Has user set -g at command line? */
  2744.                     {    /* yes => update MediaSize to remain consistent */
  2745.                         gx_device_set_width_height(dev, dev->width, 
  2746.                             dev->height);
  2747.                     }
  2748.                     else
  2749.                     {    /* no => update width/height to remain consistent */
  2750.                         gx_device_set_media_size(dev, dev->MediaSize[0], 
  2751.                             dev->MediaSize[1]);
  2752.                     }
  2753.                 }
  2754.  
  2755.                 xdev->rport = (struct RastPort *)AllocVec(
  2756.                     sizeof(struct RastPort), MEMF_ANY);
  2757.                 if (xdev->rport)
  2758.                 {
  2759.                     const sigset_t    trapped = sigmask(SIGINT);
  2760.                     struct BitMap    DummyBitMap;
  2761.                     UWORD        DummyLine[12];
  2762.  
  2763.                     InitRastPort(xdev -> rport);
  2764.  
  2765.                         /* Compensate for the non-printable are of the page:
  2766.                          * 
  2767.                          * Unfortunately the standard Amiga printer drivers 
  2768.                          * are too poorly designed for that matter and do just 
  2769.                          * provide MaxXDots/MaxYDots, which is obviously not 
  2770.                          * enough to place the image correctly on the paper.
  2771.                          * Therefore, a good approximation seems to be to 
  2772.                          * substract half of these values on either side of
  2773.                          * the bitmap. Then a SPECIAL_NOPRINT dump is 
  2774.                          * performed to see what the actual printsize in 
  2775.                          * printerpixels would be. If this reveals, that the
  2776.                          * user has set preferences to produce a smaller
  2777.                          * image the margins will be ignored for the real dump.
  2778.                          * (Of course, one could compute all this without the
  2779.                          * NOPRINT dump, it's just more convenient this way 
  2780.                          * and blames the OS for all its buggy calculations ;-)
  2781.                          *
  2782.                          * In general this provides a policy which tries to do
  2783.                          * a 1:1 dump prior to exact placement (which rules if
  2784.                          * the real non-printable margins of the printer don't
  2785.                          * fit to the estimated halves on either side).
  2786.                          *
  2787.                          * One should probably use the gs printer drivers 
  2788.                          * anyway if accuracy matters!
  2789.                          */
  2790.  
  2791. /* NOTE: Unfortunately the printer device corrects the aspect ratio based on 
  2792.  * a ModeID instead of just the supplied dimensions when a dump without 
  2793.  * SPECIAL_ASPECT is requested and ABSOLUTE_DIMENSIONS is set in preferences. 
  2794.  * Therefore it seems best to supply a ModeID which fits to the default gs 
  2795.  * device settings as well as to many printers (1:1); this may lead to wrong 
  2796.  * but expectable results in case the device resolution has a different aspect 
  2797.  * ratio.
  2798.  * TODO: Maybe the device settings could be 'normalized' to 1:1 to circumvent 
  2799.  * this problem.
  2800.  */
  2801.  
  2802.                     xdev->printer->io_Command    = PRD_DUMPRPORT;
  2803.                     xdev->printer->io_RastPort    = xdev->rport;
  2804.                     xdev->printer->io_Modes        = VGAPRODUCT_KEY;    /* 1:1 */
  2805.                     xdev->printer->io_SrcX    = 
  2806.                         MAX((LONG)(dev->width - PED->ped_MaxXDots), 0) / 2;
  2807.                     xdev->printer->io_SrcY    = PED->ped_MaxYDots ?
  2808.                         MAX((LONG)(dev->height - PED->ped_MaxYDots), 0) / 2 
  2809.                         : 0;
  2810.                     xdev->printer->io_SrcWidth    = 
  2811.                         MIN(dev->width, PED->ped_MaxXDots);
  2812.                     xdev->printer->io_SrcHeight    = PED->ped_MaxYDots ? 
  2813.                         MIN(dev->height, PED->ped_MaxYDots) : dev->height;
  2814.                     xdev->printer->io_DestCols    = xdev->printer->io_SrcWidth;
  2815.                     xdev->printer->io_DestRows    = xdev->printer->io_SrcHeight;
  2816.                     xdev->printer->io_Special    = (SPECIAL_NOPRINT);
  2817.  
  2818.                         /* Cook up a dummy bitmap to keep
  2819.                          * `smart' drivers from complaining.
  2820.                          */
  2821.  
  2822.                     InitBitMap(&DummyBitMap, 12, dev->width, dev->height);
  2823.  
  2824.                     DummyBitMap.Planes[0] = (PLANEPTR)&DummyLine;
  2825.  
  2826.                     xdev->rport->BitMap = &DummyBitMap;
  2827.  
  2828.                         /* Don't let them stop us now! */
  2829. #ifdef IXEMUL
  2830.                     sigprocmask(SIG_BLOCK,&trapped,NULL);
  2831. #endif
  2832.                         /* Ask for it... */
  2833.  
  2834.                     if(!DoIO((struct IORequest *)xdev -> printer))
  2835.                     {
  2836.                         LONG                 Depth,
  2837.                                          NumColours,
  2838.                                          CubeSize;
  2839.  
  2840.                             /* Unblock ^C signal. */
  2841. #ifdef IXEMUL
  2842.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2843. #endif
  2844.                              /* Provide everything to perform the real dump:
  2845.                               *
  2846.                               * Check wether preference settings leaded to
  2847.                               * an image smaller than the largest possible one.
  2848.                               * If this is the case the margins determined
  2849.                               * above are ignored, as the image will most 
  2850.                               * likely fit within the printable area of the
  2851.                               * page (except for those rare cases where a
  2852.                               * printout is requested whith boundaries just
  2853.                               * smaller than the largest possible ones by 
  2854.                               * values within the determined margins).
  2855.                               */
  2856.  
  2857.                         if (xdev->printer->io_DestCols 
  2858.                             < xdev->printer->io_SrcWidth)
  2859.                         {    /* reset dimensions to print the entire image */
  2860.                             xdev->printer->io_SrcX    = 0;
  2861.                             xdev->printer->io_SrcWidth    = xdev->width;
  2862.                         }
  2863.                         if (xdev->printer->io_DestRows 
  2864.                             < xdev->printer->io_SrcHeight)
  2865.                         {    /* reset dimensions to print the entire image */
  2866.                             xdev->printer->io_SrcY    = 0;
  2867.                             xdev->printer->io_SrcHeight    = xdev->height;
  2868.                         }
  2869.                         xdev->printer->io_DestCols    = 
  2870.                             xdev->printer->io_SrcWidth;
  2871.                         xdev->printer->io_DestRows    = 
  2872.                             xdev->printer->io_SrcHeight;
  2873.                         xdev->printer->io_Special    &= ~(SPECIAL_NOPRINT);
  2874.  
  2875.                             /* Set up the default colour values. */
  2876.  
  2877.                         if(Prefs -> PrintShade == SHADE_BW)
  2878.                         {
  2879.                             Depth        = 1;
  2880.                             NumColours    = 2;
  2881.                             CubeSize    = 0;
  2882.                         }
  2883.                         else
  2884.                         {
  2885.                             Depth        = 12;
  2886.                             NumColours    = 4096;
  2887.                             CubeSize    = 16;
  2888.                         }
  2889.  
  2890.                             /* Try to allocate a suitable bitmap.
  2891.                              * If an allocation fails, rescale the
  2892.                              * colour cube and bitmap depth and
  2893.                              * retry. Minimum are eight colours.
  2894.                              */
  2895.  
  2896.                         do
  2897.                         {
  2898.                                 /* Try to allocate the raster... */
  2899.  
  2900.                             xdev->bitmap = CreateBitMap(xdev->width, 
  2901.                                 xdev->height, Depth, NULL, NULL, TRUE);
  2902.                             if (!(xdev->bitmap))
  2903.                             {
  2904.                                     /* Any chance to rescale the cube? */
  2905.  
  2906.                                 if(Depth < 2)
  2907.                                     break;
  2908.                                 else
  2909.                                 {
  2910.                                         /* One plane less... */
  2911.  
  2912.                                     Depth--;
  2913.  
  2914.                                         /* Rescale the cube. */
  2915.  
  2916.                                     while(CubeSize >= 2)
  2917.                                     {
  2918.                                         NumColours = CubeSize * CubeSize 
  2919.                                             * CubeSize;
  2920.                                         if(NumColours <= (1 << Depth))
  2921.                                             break;
  2922.                                         else
  2923.                                             CubeSize--;
  2924.                                     }
  2925.  
  2926.                                         /* Less than eight colours? */
  2927.  
  2928.                                     if(CubeSize < 2)
  2929.                                         break;
  2930.                                 }
  2931.                             }
  2932.                         }
  2933.                         while(!xdev -> bitmap);
  2934.  
  2935.                             /* Got the bitmap? */
  2936.  
  2937.                         if(xdev -> bitmap)
  2938.                         {
  2939.                                 /* Allocate a suitable colour map. */
  2940.  
  2941.                             xdev -> colormap = GetColorMap(NumColours);
  2942.                             if(xdev -> colormap)
  2943.                             {
  2944.                                     /* Black & white only? */
  2945.  
  2946.                                 if(NumColours == 2)
  2947.                                 {
  2948.                                     SetRGB4CM(xdev -> colormap,0,0x0,0x0,0x0);
  2949.                                     SetRGB4CM(xdev -> colormap,1,0xF,0xF,0xF);
  2950.                                 }
  2951.                                 else
  2952.                                 {
  2953.                                     LONG i = 0,r,g,b,max = CubeSize - 1;
  2954.  
  2955.                                         /* Fill in the colour cube. */
  2956.  
  2957.                                     for(r = 0 ; r < CubeSize ; r++)
  2958.                                     {
  2959.                                         for(g = 0 ; g < CubeSize ; g++)
  2960.                                         {
  2961.                                             for(b = 0 ; b < CubeSize ; b++)
  2962.                                                 SetRGB4CM(xdev->colormap, i++, 
  2963.                                                     (15 * r) / max, 
  2964.                                                     (15 * g) / max, 
  2965.                                                     (15 * b) / max);
  2966.                                         }
  2967.                                     }
  2968.  
  2969.                                     set_colour_printer_device(
  2970.                                         (gx_device_amiga *)dev, CubeSize);
  2971.                                 }
  2972.  
  2973.                                 xdev->printer->io_ColorMap = xdev->colormap;
  2974.                                 xdev->rport->BitMap = xdev->bitmap;
  2975.  
  2976.                                 return(0);
  2977.                             }
  2978.                             else
  2979.                                 eprintf("Ghostscript: failed to allocate "
  2980.                                     "colour map\n");
  2981.                         }
  2982.                         else
  2983.                         {
  2984.                             char buffer[256];
  2985.  
  2986.                             sprintf(buffer, "Ghostscript: failed to allocate "
  2987.                                 "raster (wanted %ld, largest %ld)\n", 
  2988.                                 (dev->width + 15) / 8 * dev->height * Depth, 
  2989.                                 AvailMem(MEMF_ANY | MEMF_LARGEST));
  2990.  
  2991.                             eprintf(buffer);
  2992.                         }
  2993.                     }
  2994.                     else
  2995.                     {
  2996. #ifdef IXEMUL
  2997.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2998. #endif
  2999.                         PrintPrinterError("Ghostscript: failed to query "
  3000.                             "printer page size ", xdev->printer->io_Error);
  3001.                     }
  3002.                 }
  3003.                 else
  3004.                     eprintf("Ghostscript: failed to allocate raster port\n");
  3005.             }
  3006.             else
  3007.             {
  3008.                 PrintPrinterError("Ghostscript: printer.device ", 
  3009.                     xdev->printer->io_Error);
  3010.             }
  3011.         }
  3012.         else
  3013.             eprintf("Ghostscript: failed to allocate device driver\n");
  3014.     }
  3015.     else
  3016.         eprintf("Ghostscript: failed to create io port\n");
  3017.  
  3018.     return_error(gs_error_unknownerror);
  3019. }
  3020.  
  3021.     /* amiga_output_page_printer(gx_device *dev,int,int):
  3022.      *
  3023.      *    Send a bitmap to the printer.
  3024.      */
  3025.  
  3026. private int
  3027. amiga_output_page_printer(gx_device *dev,int num_copies,int flush)
  3028. {
  3029.     const sigset_t trapped = sigmask(SIGINT);
  3030.     int result = gs_error_unknownerror, i;
  3031.     ULONG Signals;
  3032.  
  3033.         /* We cannot possibly allow being interrupted in the middle
  3034.          * of a raster dump!
  3035.          */
  3036. #ifdef IXEMUL
  3037.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  3038. #endif
  3039.     for(i = 0 ; i < num_copies ; i++)
  3040.     {
  3041.         SetSignal(0,SIGBREAKF_CTRL_C | (1L << xdev -> port -> mp_SigBit));
  3042.  
  3043.         SendIO((struct IORequest *)xdev -> printer);
  3044.  
  3045.         Signals = Wait(SIGBREAKF_CTRL_C | (1L << xdev -> port -> mp_SigBit));
  3046.  
  3047.         if(Signals & SIGBREAKF_CTRL_C)
  3048.         {
  3049.             if(!CheckIO((struct IORequest *)xdev -> printer))
  3050.                 AbortIO((struct IORequest *)xdev -> printer);
  3051.  
  3052.             WaitIO((struct IORequest *)xdev -> printer);
  3053.  
  3054.             eprintf("Ghostscript: printing aborted\n");
  3055.  
  3056.             result = gs_error_unknownerror;
  3057.  
  3058.             break;
  3059.         }
  3060.  
  3061.         if(Signals & (1L << xdev -> port -> mp_SigBit))
  3062.         {
  3063.             if(WaitIO((struct IORequest *)xdev -> printer))
  3064.             {
  3065.                 result = gs_error_unknownerror;
  3066.  
  3067.                 PrintPrinterError("Ghostscript: failed to print raster ", 
  3068.                     xdev->printer->io_Error);
  3069.  
  3070.                 break;
  3071.             }
  3072.             else
  3073.                 result = 0;
  3074.         }
  3075.     }
  3076. #ifdef IXEMUL
  3077.     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3078. #endif
  3079.  
  3080.     if (result)
  3081.         return_error(result);
  3082.     else
  3083.         return (0);
  3084. }
  3085.  
  3086.     /* amiga_close_printer(gx_device *dev):
  3087.      *
  3088.      *    Close the printer driver.
  3089.      */
  3090.  
  3091. private int
  3092. amiga_close_printer(gx_device *dev)
  3093. {
  3094.     if(xdev -> bitmap)
  3095.     {
  3096.         DeleteBitMap(xdev -> bitmap,TRUE);
  3097.  
  3098.         xdev -> bitmap = NULL;
  3099.     }
  3100.  
  3101.     if(xdev -> rport)
  3102.     {
  3103.         FreeVec(xdev -> rport);
  3104.  
  3105.         xdev -> rport = NULL;
  3106.     }
  3107.  
  3108.     if(xdev -> colormap)
  3109.     {
  3110.         FreeColorMap(xdev -> colormap);
  3111.  
  3112.         xdev -> colormap = NULL;
  3113.     }
  3114.  
  3115.     if(xdev -> printer)
  3116.     {
  3117.         if(xdev -> printer -> io_Device)
  3118.             CloseDevice((struct IORequest *)xdev -> printer);
  3119.  
  3120.         DeleteIORequest(xdev -> printer);
  3121.  
  3122.         xdev -> printer = NULL;
  3123.     }
  3124.  
  3125.     if(xdev -> port)
  3126.     {
  3127.         DeleteMsgPort(xdev -> port);
  3128.  
  3129.         xdev -> port = NULL;
  3130.     }
  3131.  
  3132.     return(0);
  3133. }
  3134.  
  3135.     /* amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data):
  3136.      *
  3137.      *    Read the raster bits into a buffer.
  3138.      */
  3139.  
  3140. private int
  3141. amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data)
  3142. {
  3143.     if(y < 0 || y > xdev -> height)
  3144.         return_error(gs_error_unknownerror);
  3145.     else
  3146.     {
  3147.         if(actual_data)
  3148.             *actual_data = (byte *)(xdev -> bitmap -> Planes[0] + xdev -> bitmap -> BytesPerRow * y);
  3149.         else
  3150.             memcpy(str,xdev -> bitmap -> Planes[0] + xdev -> bitmap -> BytesPerRow * y,xdev -> bitmap -> BytesPerRow);
  3151.  
  3152.         return(0);
  3153.     }
  3154. }
  3155.  
  3156.     /* amiga_open(gx_device *dev,ULONG Mode):
  3157.      *
  3158.      *    Open a custom screen.
  3159.      */
  3160.  
  3161. private int
  3162. amiga_open(gx_device *dev,ULONG Mode)
  3163. {
  3164.     struct DisplayInfo    DisplayInfo;
  3165.     struct DimensionInfo    DimensionInfo;
  3166.  
  3167.         /* Get the display dimensions. */
  3168.  
  3169.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode) && GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,Mode))
  3170.     {
  3171.             /* Two shades only, black & white */
  3172.  
  3173.         STATIC struct ColorSpec Colours[] =
  3174.         {
  3175.             { 0, 0x0000, 0x0000, 0x0000, },
  3176.             { 1, 0xFFFF, 0xFFFF, 0xFFFF, },
  3177.             { -1, },
  3178.         };
  3179.  
  3180.         LONG    i,cube_size,max;
  3181.         LONG    ScreenDepth;
  3182.  
  3183.             /* Start up with a maximum depth display. */
  3184.  
  3185.         ScreenDepth = DimensionInfo . MaxDepth;
  3186.  
  3187.             /* Check to see whether we will be able to
  3188.              * build a colour display or not.
  3189.              */
  3190.  
  3191.         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  3192.         {
  3193.             if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3194.                 break;
  3195.         }
  3196.  
  3197.             /* Got enough colours? */
  3198.  
  3199.         if(cube_size != 1)
  3200.             set_colour_device((gx_device_amiga *)dev,cube_size,NULL);
  3201.         else
  3202.         {
  3203.             ScreenDepth = 1;
  3204.  
  3205.             set_mono_device((gx_device_amiga *)dev);
  3206.         }
  3207.  
  3208.             /* Adjust device to screen resolution. */
  3209.  
  3210.         if (!ResolutionSwitch)    /* Has user set -r at command line? */
  3211.         {    /* no */
  3212.     
  3213.                 /* Compute the dots_per_inch resolution from the 
  3214.                  * ticks_per_pixel resolution in the display database.
  3215.                  * See #define MAGIC_... for a comment.
  3216.                  */
  3217.  
  3218.             if (DisplayInfo.Resolution.x && DisplayInfo.Resolution.y)
  3219.             {
  3220.                 dev->x_pixels_per_inch = MAGIC_DPI_BASE_VALUE 
  3221.                     / DisplayInfo.Resolution.x;
  3222.                 dev->y_pixels_per_inch = MAGIC_DPI_BASE_VALUE 
  3223.                     / DisplayInfo.Resolution.y;
  3224.  
  3225.                 if (GeometrySwitch)    /* Has user set -g at command line? */
  3226.                 {    /* yes => update MediaSize to remain consistent */
  3227.                     gx_device_set_width_height(dev, dev->width, 
  3228.                         dev->height);
  3229.                 }
  3230.                 else
  3231.                 {    /* no => update width/height to remain consistent */
  3232.                     gx_device_set_media_size(dev, dev->MediaSize[0], 
  3233.                         dev->MediaSize[1]);
  3234.                 }
  3235.             }
  3236.         }
  3237.  
  3238.             /* Ensure the computed values will fit on the screen */
  3239.             
  3240.         if (dev->width < DimensionInfo.MinRasterWidth)
  3241.             gx_device_set_width_height(dev, DimensionInfo.MinRasterWidth, 
  3242.                 dev->height);
  3243.         if (dev->width > DimensionInfo.MaxRasterWidth)
  3244.             gx_device_set_width_height(dev, DimensionInfo.MaxRasterWidth, 
  3245.                 dev->height);
  3246.         if (dev->height < DimensionInfo.MinRasterHeight)
  3247.             gx_device_set_width_height(dev, dev->width, 
  3248.                 DimensionInfo.MinRasterHeight);
  3249.         if (dev->height > DimensionInfo.MaxRasterHeight)
  3250.             gx_device_set_width_height(dev, dev->width, 
  3251.                 DimensionInfo.MaxRasterHeight);
  3252.  
  3253.             /* Try to open a custom screen; if this fails, try to
  3254.              * rescale the colour cube and retry.
  3255.              */
  3256.  
  3257.         do
  3258.         {
  3259.             xdev -> screen = OpenScreenTags(NULL,
  3260.                 SA_Depth,    ScreenDepth,
  3261.                 SA_Overscan,    OSCAN_TEXT,
  3262.                 SA_Quiet,    TRUE,
  3263.                 SA_Behind,    TRUE,
  3264.                 SA_DisplayID,    Mode,
  3265.                 SA_Colors,    (ULONG)Colours,
  3266.                 SA_AutoScroll,    TRUE,
  3267.                 SA_ShowTitle,    FALSE,
  3268.                 SA_Title,    (ULONG)"Ghostscript Amiga output screen",
  3269.                 SA_Width,    dev->width,
  3270.                 SA_Height,    dev->height,
  3271.                 TAG_DONE);
  3272.             if(!(xdev -> screen))
  3273.             {
  3274.                 if(ScreenDepth < 2)
  3275.                     break;
  3276.                 else
  3277.                 {
  3278.                     ScreenDepth--;
  3279.  
  3280.                         /* Check to see whether we will be able to
  3281.                          * build a colour display or not.
  3282.                          */
  3283.  
  3284.                     while(cube_size >= 2)
  3285.                     {
  3286.                         if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3287.                             break;
  3288.                         else
  3289.                             cube_size--;
  3290.                     }
  3291.  
  3292.                         /* Got enough colours? */
  3293.  
  3294.                     if(cube_size == 1 || ScreenDepth == 1)
  3295.                     {
  3296.                             /* Obviously not. */
  3297.  
  3298.                         ScreenDepth = 1;
  3299.  
  3300.                         set_mono_device((gx_device_amiga *)dev);
  3301.                     }
  3302.                 }
  3303.             }
  3304.         }
  3305.         while(!xdev -> screen);
  3306.  
  3307.             /* Did we succeed in opening the screen? */
  3308.  
  3309.         if(xdev -> screen)
  3310.         {
  3311.                 /* OpenScreenTags above really shouldn't have changed these,
  3312.                  * but better be safe...
  3313.                  */
  3314.                 
  3315.             gx_device_set_width_height(dev, xdev->screen->Width, 
  3316.                 xdev->screen->Height);
  3317.  
  3318.             xdev -> window = OpenWindowTags(NULL,
  3319.                 WA_Left,    0,
  3320.                 WA_Top,        0,
  3321.                 WA_Width,    dev -> width,
  3322.                 WA_Height,    dev -> height,
  3323.                 WA_Backdrop,    TRUE,
  3324.                 WA_RMBTrap,    TRUE,
  3325.                 WA_Borderless,    TRUE,
  3326.                 WA_CustomScreen,(ULONG)(xdev -> screen),
  3327.                 TAG_DONE);
  3328.             if(xdev -> window)
  3329.             {
  3330.                 xdev -> rport    = xdev -> window -> RPort;
  3331.             }
  3332.             else
  3333.             {
  3334.                 xdev -> rport    = &xdev -> screen -> RastPort;
  3335.             }
  3336.  
  3337.                 /* Establish defaults. */
  3338.  
  3339.             DarkPen        = 0;
  3340.             LightPen    = 1;
  3341.  
  3342.             SetBPen(xdev -> rport,0);
  3343.             SetDrMd(xdev -> rport,JAM2);
  3344.  
  3345.                 /* Create the temporary drawing area. */
  3346.  
  3347.             xdev -> temp_rport = CreateTempRPort(xdev -> rport);
  3348.             if(xdev -> temp_rport)
  3349.             {
  3350.                 xdev -> temp_array = (UBYTE *)AllocVec((dev -> width + 15) 
  3351.                     & ~15, MEMF_ANY);
  3352.                 if(xdev -> temp_array)
  3353.                 {
  3354.                         /* Colour output enabled? */
  3355.  
  3356.                     if(xdev -> cube_size > 0)
  3357.                     {
  3358.                         LONG r,g,b,max = xdev -> cube_size - 1;
  3359.  
  3360.                         i = 0;
  3361.  
  3362.                             /* Build a suitable colour map. */
  3363.  
  3364.                         if(GfxBase -> LibNode . lib_Version >= 39)
  3365.                         {
  3366.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3367.                             {
  3368.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3369.                                 {
  3370.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3371.                                         SetRGB32(&xdev -> screen -> ViewPort,i++,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max));
  3372.                                 }
  3373.                             }
  3374.                         }
  3375.                         else
  3376.                         {
  3377.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3378.                             {
  3379.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3380.                                 {
  3381.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3382.                                         SetRGB4(&xdev -> screen -> ViewPort,i++,(15 * r) / max,(15 * g) / max,(15 * b) / max);
  3383.                                 }
  3384.                             }
  3385.                         }
  3386.                     }
  3387.                 }
  3388.                 else
  3389.                 {
  3390.                     eprintf("Ghostscript: failed to allocate temporary line\n");
  3391.  
  3392.                     return_error(gs_error_unknownerror);
  3393.                 }
  3394.             }
  3395.             else
  3396.             {
  3397.                 eprintf("Ghostscript: failed to allocate temporary raster\n");
  3398.  
  3399.                 return_error(gs_error_unknownerror);
  3400.             }
  3401.  
  3402.             amiga_set_pen(dev,DarkPen);
  3403.  
  3404.             return(0);
  3405.         }
  3406.         else
  3407.             eprintf("Ghostscript: failed to open screen\n");
  3408.     }
  3409.     else
  3410.         eprintf("Ghostscript: failed to get display mode information\n");
  3411.  
  3412.     return_error(gs_error_unknownerror);
  3413. }
  3414.  
  3415.     /* amiga_output_page(gx_device *dev,int,int):
  3416.      *
  3417.      *    Page is not `buffered', just bring screen/window
  3418.      *    to the front.
  3419.      */
  3420.  
  3421. private int
  3422. amiga_output_page(gx_device *dev,int num_copies,int flush)
  3423. {
  3424.     if(xdev -> screen)
  3425.         ScreenToFront(xdev -> screen);
  3426.     else
  3427.     {
  3428.         if(xdev -> window)
  3429.             WindowToFront(xdev -> window);
  3430.     }
  3431.  
  3432.     return(0);
  3433. }
  3434.  
  3435.     /* amiga_close(gx_device *dev):
  3436.      *
  3437.      *    Close the screen and free associated resources.
  3438.      */
  3439.  
  3440. private int
  3441. amiga_close(gx_device *dev)
  3442. {
  3443.     if(xdev -> dispatcher)
  3444.     {
  3445.         const sigset_t trapped = sigmask(SIGINT);
  3446. #ifdef IXEMUL
  3447.         sigprocmask(SIG_BLOCK,&trapped,NULL);
  3448. #endif
  3449.         Forbid();
  3450.  
  3451.         Signal(xdev -> dispatcher,SIG_KILL);
  3452.  
  3453.         SetSignal(0,SIG_HANDSHAKE);
  3454.  
  3455.         Wait(SIG_HANDSHAKE);
  3456.  
  3457.         Permit();
  3458. #ifdef IXEMUL
  3459.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3460. #endif
  3461.     }
  3462.  
  3463.     if(xdev -> temp_array)
  3464.     {
  3465.         FreeVec(xdev -> temp_array);
  3466.  
  3467.         xdev -> temp_array = NULL;
  3468.     }
  3469.  
  3470.     if(xdev -> pens)
  3471.     {
  3472.         LONG i;
  3473.  
  3474.         for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  3475.         {
  3476.             if(xdev -> pens[i] != -1)
  3477.                 ReleasePen(xdev -> window -> WScreen -> ViewPort . ColorMap,xdev -> pens[i]);
  3478.         }
  3479.  
  3480.         FreeVec(xdev -> pens);
  3481.  
  3482.         xdev -> pens = NULL;
  3483.     }
  3484.  
  3485.     if(xdev -> temp_rport)
  3486.     {
  3487.         DeleteTempRPort(xdev -> temp_rport);
  3488.  
  3489.         xdev -> temp_rport = NULL;
  3490.     }
  3491.  
  3492.     if(xdev -> window)
  3493.     {
  3494.         CloseWindow(xdev -> window);
  3495.  
  3496.         xdev -> window = NULL;
  3497.     }
  3498.  
  3499.     DeleteScrollers(dev);
  3500.  
  3501.     if(xdev -> super_bitmap)
  3502.     {
  3503.         DeleteBitMap(xdev -> super_bitmap,FALSE);
  3504.  
  3505.         xdev -> super_bitmap = NULL;
  3506.     }
  3507.  
  3508.     if(xdev -> screen)
  3509.     {
  3510.         CloseScreen(xdev -> screen);
  3511.  
  3512.         xdev -> screen = NULL;
  3513.     }
  3514.  
  3515.     return(0);
  3516. }
  3517.  
  3518.     /* amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color):
  3519.      *
  3520.      *    Fill a rectangle with a given colour. This one is simple as it can
  3521.      *    be done with the Amiga graphics primitives.
  3522.      */
  3523.  
  3524. private int
  3525. amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  3526. {
  3527.     fit_fill(dev, x, y, w, h);
  3528.     if(color != gx_no_color_index)
  3529.     {
  3530.         amiga_set_pen(dev,color);
  3531.  
  3532.         RectFill(xdev -> rport, x, y, (x + w - 1), (y + h - 1));
  3533.     }
  3534.  
  3535.     return(0);
  3536. }
  3537.  
  3538.     /* amiga_copy_mono():
  3539.      *
  3540.      *    Copy a monochrome image. This operation requires a bit of work as
  3541.      *    we cannot simply blit the image into the bitmap.
  3542.      */
  3543.  
  3544. private int
  3545. amiga_copy_mono(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3546. {
  3547.     LONG i,j;
  3548.  
  3549.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  3550.  
  3551.     if(zero == gx_no_color_index)
  3552.     {
  3553.         if(one != gx_no_color_index)
  3554.         {
  3555.             do
  3556.             {
  3557.                 ReadPixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3558.  
  3559.                 for(i = sourcex, j = 0 ; i < sourcex + w ; i++, j++)
  3560.                 {
  3561.                     if(base[i >> 3] & shift[i & 7])
  3562.                         xdev -> temp_array[j] = one;
  3563.                 }
  3564.  
  3565.                 WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3566.  
  3567.                 base += raster;
  3568.  
  3569.                 y++;
  3570.             }
  3571.             while(--h);
  3572.         }
  3573.     }
  3574.     else
  3575.     {
  3576.         if(one == gx_no_color_index)
  3577.         {
  3578.             do
  3579.             {
  3580.                 ReadPixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3581.  
  3582.                 for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3583.                 {
  3584.                     if(!(base[i >> 3] & shift[i & 7]))
  3585.                         xdev -> temp_array[j] = zero;
  3586.                 }
  3587.  
  3588.                 WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3589.  
  3590.                 base += raster;
  3591.  
  3592.                 y++;
  3593.             }
  3594.             while(--h);
  3595.         }
  3596.         else
  3597.         {
  3598.             do
  3599.             {
  3600.                 for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3601.                 {
  3602.                     if(base[i >> 3] & shift[i & 7])
  3603.                         xdev -> temp_array[j] = one;
  3604.                     else
  3605.                         xdev -> temp_array[j] = zero;
  3606.                 }
  3607.  
  3608.                 WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3609.  
  3610.                 base += raster;
  3611.  
  3612.                 y++;
  3613.             }
  3614.             while(--h);
  3615.         }
  3616.     }
  3617.  
  3618.     return(0);
  3619. }
  3620.  
  3621.     /* amiga_copy_color():
  3622.      *
  3623.      *    Copy a color image (oh well...). This is just the same as the
  3624.      *    copy_mono() routine.
  3625.      */
  3626.  
  3627. private int
  3628. amiga_copy_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  3629. {
  3630.     LONG i,j;
  3631.  
  3632.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  3633.  
  3634.     do
  3635.     {
  3636.         for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3637.         {
  3638.             if(base[i >> 3] & shift[i & 7])
  3639.                 xdev -> temp_array[j] = DarkPen;
  3640.             else
  3641.                 xdev -> temp_array[j] = LightPen;
  3642.         }
  3643.  
  3644.         WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3645.  
  3646.         base += raster;
  3647.  
  3648.         y++;
  3649.     }
  3650.     while(--h);
  3651.  
  3652.     return(0);
  3653. }
  3654.  
  3655.     /* amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color):
  3656.      *
  3657.      *    Draw a line between two points. This one is easy as it can be done
  3658.      *    with the Amiga graphics primitives, the only glitch is having to reset
  3659.      *    the last dot to its original colour.
  3660.      */
  3661.  
  3662. private int
  3663. amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color)
  3664. {
  3665.     if(color != gx_no_color_index && (x0 != x1 || y0 != y1))
  3666.     {
  3667.         LONG pen;
  3668.  
  3669.         pen = ReadPixel(xdev -> rport,x1,y1);
  3670.  
  3671.         amiga_set_pen(dev,color);
  3672.  
  3673.         Move(xdev -> rport,x0,y0);
  3674.         Draw(xdev -> rport,x1,y1);
  3675.  
  3676.         if(pen == color)
  3677.         {
  3678.             amiga_set_pen(dev,pen);
  3679.  
  3680.             WritePixel(xdev -> rport,x1,y1);
  3681.         }
  3682.     }
  3683.  
  3684.     return(0);
  3685. }
  3686.  
  3687.     /* amiga_copy_mono_raw():
  3688.      *
  3689.      *    Copy a monochrome image to a bitmap. Just watch the
  3690.      *    astounding number of case switches.
  3691.      */
  3692.  
  3693. private int
  3694. amiga_copy_mono_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3695. {
  3696.     LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3697.     UBYTE *line;
  3698.  
  3699.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  3700.  
  3701.     w += sourcex;
  3702.  
  3703.     line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  3704.  
  3705.     if(zero == gx_no_color_index)
  3706.     {
  3707.         if(one != gx_no_color_index)
  3708.         {
  3709.             if(one)
  3710.             {
  3711.                 do
  3712.                 {
  3713.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3714.                     {
  3715.                         if(base[i >> 3] & shift[i & 7])
  3716.                             line[j >> 3] |= shift[j & 7];
  3717.                     }
  3718.  
  3719.                     base += raster;
  3720.  
  3721.                     line += modulo;
  3722.                 }
  3723.                 while(--h);
  3724.             }
  3725.             else
  3726.             {
  3727.                 do
  3728.                 {
  3729.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3730.                     {
  3731.                         if(base[i >> 3] & shift[i & 7])
  3732.                             line[j >> 3] &= masks[j & 7];
  3733.                     }
  3734.                         base += raster;
  3735.                         line += modulo;
  3736.                 }
  3737.                 while(--h);
  3738.             }
  3739.         }
  3740.     }
  3741.     else
  3742.     {
  3743.         if(one == gx_no_color_index)
  3744.         {
  3745.             if(zero)
  3746.             {
  3747.                 do
  3748.                 {
  3749.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3750.                     {
  3751.                         if(!(base[i >> 3] & shift[i & 7]))
  3752.                             line[j >> 3] |= shift[j & 7];
  3753.                     }
  3754.  
  3755.                     base += raster;
  3756.  
  3757.                     line += modulo;
  3758.                 }
  3759.                 while(--h);
  3760.             }
  3761.             else
  3762.             {
  3763.                 do
  3764.                 {
  3765.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3766.                     {
  3767.                         if(!(base[i >> 3] & shift[i & 7]))
  3768.                             line[j >> 3] &= masks[j & 7];
  3769.                     }
  3770.  
  3771.                     base += raster;
  3772.  
  3773.                     line += modulo;
  3774.                 }
  3775.                 while(--h);
  3776.             }
  3777.         }
  3778.         else
  3779.         {
  3780.             if(one)
  3781.             {
  3782.                 do
  3783.                 {
  3784.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3785.                     {
  3786.                         if(base[i >> 3] & shift[i & 7])
  3787.                             line[j >> 3] |= shift[j & 7];
  3788.                         else
  3789.                             line[j >> 3] &= masks[j & 7];
  3790.                     }
  3791.  
  3792.                     base += raster;
  3793.  
  3794.                     line += modulo;
  3795.                 }
  3796.                 while(--h);
  3797.             }
  3798.             else
  3799.             {
  3800.                 do
  3801.                 {
  3802.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3803.                     {
  3804.                         if(base[i >> 3] & shift[i & 7])
  3805.                             line[j >> 3] &= masks[j & 7];
  3806.                         else
  3807.                             line[j >> 3] |= shift[j & 7];
  3808.                     }
  3809.  
  3810.                     base += raster;
  3811.  
  3812.                     line += modulo;
  3813.                 }
  3814.                 while(--h);
  3815.             }
  3816.         }
  3817.     }
  3818.  
  3819.     return(0);
  3820. }
  3821.  
  3822.     /* amiga_copy_color_raw():
  3823.      *
  3824.      *    Copy a color image (oh well...). This is just the same as the
  3825.      *    copy_mono() routine.
  3826.      */
  3827.  
  3828. private int
  3829. amiga_copy_color_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  3830. {
  3831.     LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3832.     UBYTE *line;
  3833.  
  3834.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  3835.  
  3836.     line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  3837.  
  3838.     w += sourcex;
  3839.  
  3840.     do
  3841.     {
  3842.         for(i = sourcex, j = x ; i < w ; i++, j++)
  3843.         {
  3844.             if(base[i >> 3] & shift[i & 7])
  3845.                 line[j >> 3] |= shift[j & 7];
  3846.             else
  3847.                 line[j >> 3] &= masks[j & 7];
  3848.         }
  3849.  
  3850.         base += raster;
  3851.  
  3852.         line += modulo;
  3853.     }
  3854.     while(--h);
  3855.  
  3856.     return(0);
  3857. }
  3858.  
  3859.     /* amiga_fill_rectangle_raw():
  3860.      *
  3861.      *    Fill a rectangular area in a bitmap.
  3862.      */
  3863.  
  3864. private int
  3865. amiga_fill_rectangle_raw(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  3866. {
  3867.     fit_fill(dev, x, y, w, h);
  3868.  
  3869.     if(color != gx_no_color_index)
  3870.     {
  3871.         UBYTE *line,startmask,endmask;
  3872.         LONG right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3873.  
  3874.         right    = x + w;
  3875.         mid    = (right >> 3) - (x >> 3);
  3876.         line    = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow + (x >> 3);
  3877.  
  3878.         x    &= 7;
  3879.         right    &= 7;
  3880.  
  3881.         if(color)
  3882.         {
  3883.             startmask    = 0xFF >> x;
  3884.             endmask        = ~(0xFF >> right);
  3885.  
  3886.             if(mid)
  3887.             {
  3888.                 UBYTE *ptr;
  3889.                 int i;
  3890.  
  3891.                 do
  3892.                 {
  3893.                     ptr = line;
  3894.  
  3895.                     *ptr++ |= startmask;
  3896.  
  3897.                     i = mid;
  3898.  
  3899.                     while(--i > 0)
  3900.                         *ptr++ = 0xFF;
  3901.  
  3902.                     *ptr |= endmask;
  3903.  
  3904.                     line += modulo;
  3905.                 }
  3906.                 while(--h);
  3907.             }
  3908.             else
  3909.             {
  3910.                 startmask &= endmask;
  3911.  
  3912.                 do
  3913.                 {
  3914.                     *line |= startmask;
  3915.  
  3916.                     line += modulo;
  3917.                 }
  3918.                 while(--h);
  3919.             }
  3920.         }
  3921.         else
  3922.         {
  3923.             startmask    = ~(0xFF >> x);
  3924.             endmask        = 0xFF >> right;
  3925.  
  3926.             if(mid)
  3927.             {
  3928.                 UBYTE *ptr;
  3929.                 LONG i;
  3930.  
  3931.                 do
  3932.                 {
  3933.                     ptr = line;
  3934.  
  3935.                     *ptr++ &= startmask;
  3936.  
  3937.                     i = mid;
  3938.  
  3939.                     while(--i > 0)
  3940.                         *ptr++ = 0x00;
  3941.  
  3942.                     *ptr &= endmask;
  3943.  
  3944.                     line += modulo;
  3945.                 }
  3946.                 while(--h);
  3947.             }
  3948.             else
  3949.             {
  3950.                 startmask |= endmask;
  3951.  
  3952.                 do
  3953.                 {
  3954.                     *line &= startmask;
  3955.  
  3956.                     line += modulo;
  3957.                 }
  3958.                 while(--h);
  3959.             }
  3960.         }
  3961.     }
  3962.  
  3963.     return(0);
  3964. }
  3965.  
  3966.     /* amiga_draw_line_raw():
  3967.      *
  3968.      *    Draw a hair line, your basic DDA algorithm;
  3969.      *    keep your fingers crossed.
  3970.      */
  3971.  
  3972. private int
  3973. amiga_draw_line_raw(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  3974. {
  3975.     if(color != gx_no_color_index && (x != x1 || y != y1))
  3976.     {
  3977.         short xstep,ystep,dx,dy,diff,modulo;
  3978.         UBYTE *line,*plane,pen;
  3979.         LONG last;
  3980.  
  3981.         modulo    = xdev -> rport -> BitMap -> BytesPerRow;
  3982.         plane    = xdev -> rport -> BitMap -> Planes[0];
  3983.  
  3984.         line    = &plane[y1 * modulo];
  3985.         last    = y1;
  3986.         pen    = line[x1 >> 3] & (x1 & 7);
  3987.  
  3988.         dx = x1 - x;
  3989.         dy = y1 - y;
  3990.  
  3991.         if(dx < 0)
  3992.         {
  3993.             dx = -dx;
  3994.             dy = -dy;
  3995.  
  3996.             x = x1;
  3997.             y = y1;
  3998.         }
  3999.  
  4000.         if(y != last)
  4001.             line = &plane[(last = y) * modulo];
  4002.  
  4003.         if(color)
  4004.         {
  4005.             line[x >> 3] |= shift[x & 7];
  4006.  
  4007.             xstep = ystep = 0;
  4008.  
  4009.             if(dy < 0)
  4010.             {
  4011.                 if(dx > -dy)
  4012.                 {
  4013.                     diff = -dx / 2;
  4014.  
  4015.                     do
  4016.                     {
  4017.                         xstep++;
  4018.  
  4019.                         if(diff > 0)
  4020.                         {
  4021.                             ystep--;
  4022.  
  4023.                             diff = diff - dy - dx;
  4024.                         }
  4025.                         else
  4026.                             diff -= dy;
  4027.  
  4028.                         {
  4029.                             LONG x1 = x + xstep,y1 = y + ystep;
  4030.  
  4031.                             if(y1 != last)
  4032.                                 line = &plane[(last = y1) * modulo];
  4033.  
  4034.                             line[x1 >> 3] |= shift[x1 & 7];
  4035.                         }
  4036.                     }
  4037.                     while(xstep < dx);
  4038.                 }
  4039.                 else
  4040.                 {
  4041.                     if(dx == -dy)
  4042.                         diff = 0;
  4043.                     else
  4044.                         diff = -dy / 2;
  4045.  
  4046.                     do
  4047.                     {
  4048.                         ystep--;
  4049.  
  4050.                         if(diff > 0)
  4051.                             diff -= dx;
  4052.                         else
  4053.                         {
  4054.                             xstep++;
  4055.  
  4056.                             diff = diff - dy - dx;
  4057.                         }
  4058.  
  4059.                         {
  4060.                             LONG x1 = x + xstep,y1 = y + ystep;
  4061.  
  4062.                             if(y1 != last)
  4063.                                 line = &plane[(last = y1) * modulo];
  4064.  
  4065.                             line[x1 >> 3] |= shift[x1 & 7];
  4066.                         }
  4067.                     }
  4068.                     while(ystep > dy);
  4069.                 }
  4070.             }
  4071.             else
  4072.             {
  4073.                 if(dx > dy)
  4074.                 {
  4075.                     diff = -dx / 2;
  4076.  
  4077.                     do
  4078.                     {
  4079.                         xstep++;
  4080.  
  4081.                         if(diff > 0)
  4082.                         {
  4083.                             ystep++;
  4084.  
  4085.                             diff = diff + dy - dx;
  4086.                         }
  4087.                         else
  4088.                             diff += dy;
  4089.  
  4090.                         {
  4091.                             LONG x1 = x + xstep,y1 = y + ystep;
  4092.  
  4093.                             if(y1 != last)
  4094.                                 line = &plane[(last = y1) * modulo];
  4095.  
  4096.                             line[x1 >> 3] |= shift[x1 & 7];
  4097.                         }
  4098.                     }
  4099.                     while(xstep < dx);
  4100.                 }
  4101.                 else
  4102.                 {
  4103.                     if(dx == dy)
  4104.                         diff = 0;
  4105.                     else
  4106.                         diff = dy / 2;
  4107.  
  4108.                     do
  4109.                     {
  4110.                         ystep++;
  4111.  
  4112.                         if(diff > 0)
  4113.                             diff -= dx;
  4114.                         else
  4115.                         {
  4116.                             xstep++;
  4117.  
  4118.                             diff = diff + dy - dx;
  4119.                         }
  4120.  
  4121.                         {
  4122.                             LONG x1 = x + xstep,y1 = y + ystep;
  4123.  
  4124.                             if(y1 != last)
  4125.                                 line = &plane[(last = y1) * modulo];
  4126.  
  4127.                             line[x1 >> 3] |= shift[x1 & 7];
  4128.                         }
  4129.                     }
  4130.                     while(ystep < dy);
  4131.                 }
  4132.             }
  4133.  
  4134.             if(!pen)
  4135.             {
  4136.                 if(y1 != last)
  4137.                     line = &plane[(last = y1) * modulo];
  4138.  
  4139.                 line[x1 >> 3] &= masks[x1 & 7];
  4140.             }
  4141.         }
  4142.         else
  4143.         {
  4144.             line[x >> 3] &= masks[x & 7];
  4145.  
  4146.             xstep = ystep = 0;
  4147.  
  4148.             if(dy < 0)
  4149.             {
  4150.                 if(dx > -dy)
  4151.                 {
  4152.                     diff = -dx / 2;
  4153.  
  4154.                     do
  4155.                     {
  4156.                         xstep++;
  4157.  
  4158.                         if(diff > 0)
  4159.                         {
  4160.                             ystep--;
  4161.  
  4162.                             diff = diff - dy - dx;
  4163.                         }
  4164.                         else
  4165.                             diff -= dy;
  4166.  
  4167.                         {
  4168.                             LONG x1 = x + xstep,y1 = y + ystep;
  4169.  
  4170.                             if(y1 != last)
  4171.                                 line = &plane[(last = y1) * modulo];
  4172.  
  4173.                             line[x1 >> 3] &= masks[x1 & 7];
  4174.                         }
  4175.                     }
  4176.                     while(xstep < dx);
  4177.                 }
  4178.                 else
  4179.                 {
  4180.                     if(dx == -dy)
  4181.                         diff = 0;
  4182.                     else
  4183.                         diff = -dy / 2;
  4184.  
  4185.                     do
  4186.                     {
  4187.                         ystep--;
  4188.  
  4189.                         if(diff > 0)
  4190.                             diff -= dx;
  4191.                         else
  4192.                         {
  4193.                             xstep++;
  4194.  
  4195.                             diff = diff - dy - dx;
  4196.                         }
  4197.  
  4198.                         {
  4199.                             LONG x1 = x + xstep,y1 = y + ystep;
  4200.  
  4201.                             if(y1 != last)
  4202.                                 line = &plane[(last = y1) * modulo];
  4203.  
  4204.                             line[x1 >> 3] &= masks[x1 & 7];
  4205.                         }
  4206.                     }
  4207.                     while(ystep > dy);
  4208.                 }
  4209.             }
  4210.             else
  4211.             {
  4212.                 if(dx > dy)
  4213.                 {
  4214.                     diff = -dx / 2;
  4215.  
  4216.                     do
  4217.                     {
  4218.                         xstep++;
  4219.  
  4220.                         if(diff > 0)
  4221.                         {
  4222.                             ystep++;
  4223.  
  4224.                             diff = diff + dy - dx;
  4225.                         }
  4226.                         else
  4227.                             diff += dy;
  4228.  
  4229.                         {
  4230.                             LONG x1 = x + xstep,y1 = y + ystep;
  4231.  
  4232.                             if(y1 != last)
  4233.                                 line = &plane[(last = y1) * modulo];
  4234.  
  4235.                             line[x1 >> 3] &= masks[x1 & 7];
  4236.                         }
  4237.                     }
  4238.                     while(xstep < dx);
  4239.                 }
  4240.                 else
  4241.                 {
  4242.                     if(dx == dy)
  4243.                         diff = 0;
  4244.                     else
  4245.                         diff =  dy / 2;
  4246.  
  4247.                     do
  4248.                     {
  4249.                         ystep++;
  4250.  
  4251.                         if(diff > 0)
  4252.                             diff -= dx;
  4253.                         else
  4254.                         {
  4255.                             xstep++;
  4256.  
  4257.                             diff = diff + dy - dx;
  4258.                         }
  4259.  
  4260.                         {
  4261.                             LONG x1 = x + xstep,y1 = y + ystep;
  4262.  
  4263.                             if(y1 != last)
  4264.                                 line = &plane[(last = y1) * modulo];
  4265.  
  4266.                             line[x1 >> 3] &= masks[x1 & 7];
  4267.                         }
  4268.                     }
  4269.                     while(ystep < dy);
  4270.                 }
  4271.             }
  4272.  
  4273.             if(pen)
  4274.             {
  4275.                 if(y1 != last)
  4276.                     line = &plane[(last = y1) * modulo];
  4277.  
  4278.                 line[x1 >> 3] |= pen;
  4279.             }
  4280.         }
  4281.     }
  4282.  
  4283.     return(0);
  4284. }
  4285.  
  4286.     /* amiga_open_ilbm(gx_device *dev):
  4287.      *
  4288.      *    Open the ilbm device.
  4289.      */
  4290.  
  4291. private int
  4292. amiga_open_ilbm(gx_device *dev)
  4293. {
  4294.     xdev -> rport = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY);
  4295.     if(xdev -> rport)
  4296.     {
  4297.         InitRastPort(xdev -> rport);
  4298.  
  4299.         xdev -> bitmap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY);
  4300.         if(xdev -> bitmap)
  4301.         {
  4302.             InitBitMap(xdev -> bitmap,1,xdev -> width,xdev -> height);
  4303.  
  4304.             xdev -> bitplane = AllocVec(xdev -> bitmap -> Rows * xdev -> bitmap -> BytesPerRow,MEMF_ANY | MEMF_CLEAR);
  4305.             if(xdev -> bitplane)
  4306.             {
  4307.                 xdev -> bitmap -> Planes[0]    = xdev -> bitplane;
  4308.                 xdev -> rport -> BitMap        = xdev -> bitmap;
  4309.                 xdev -> page_count        = 1;
  4310.  
  4311.                 DarkPen        = 0;
  4312.                 LightPen    = 1;
  4313.  
  4314.                 return(0);
  4315.             }
  4316.             else
  4317.             {
  4318.                 char buffer[256];
  4319.  
  4320.                 sprintf(buffer,"Ghostscript: failed to allocate raster "
  4321.                     "(wanted %ld, largest %ld)\n", 
  4322.                     (long)(xdev->bitmap->Rows * xdev->bitmap->BytesPerRow),
  4323.                     AvailMem(MEMF_ANY | MEMF_LARGEST));
  4324.  
  4325.                 eprintf(buffer);
  4326.             }
  4327.         }
  4328.         else
  4329.             eprintf("Ghostscript: failed to allocate bitmap\n");
  4330.     }
  4331.     else
  4332.         eprintf("Ghostscript: failed to allocate raster port\n");
  4333.  
  4334.     return_error(gs_error_unknownerror);
  4335. }
  4336.  
  4337.     /* amiga_output_page_ilbm(gx_device *dev,int,int):
  4338.      *
  4339.      *    Send a bitmap to an IFF-ILBM file.
  4340.      */
  4341.  
  4342. private int
  4343. amiga_output_page_ilbm(gx_device *dev,int num_copies,int flush)
  4344. {
  4345.     const sigset_t trapped = sigmask(SIGINT);
  4346.     char buffer[270];
  4347.  
  4348.     sprintf(buffer,"%s_%04d.ilbm",xdev -> file_name,xdev -> page_count);
  4349.  
  4350.     fprintf(stdout,"\n\033[ASaving page Nº%d to \"%s\"...\033[K",xdev -> page_count,buffer);
  4351.     fflush(stdout);
  4352. #ifdef IXEMUL
  4353.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  4354. #endif
  4355.     if(SaveBitMap(buffer,xdev -> bitmap,xdev -> width,xdev -> height,(UWORD)xdev -> x_pixels_per_inch,xdev -> y_pixels_per_inch))
  4356.     {
  4357.         fprintf(stdout,"\n\033[APage saved to file \"%s\".\033[K\n",buffer);
  4358.  
  4359.         xdev -> page_count++;
  4360.  
  4361. #ifdef IXEMUL
  4362.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  4363. #endif
  4364.  
  4365.         return (0);
  4366.     }
  4367.     else
  4368.     {
  4369.         eprintf("\n\033[AGhostscript: error saving page\033[K");
  4370.  
  4371. #ifdef IXEMUL
  4372.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  4373. #endif
  4374.  
  4375.         return_error(gs_error_unknownerror);
  4376.     }
  4377. }
  4378.  
  4379.     /* amiga_close_ilbm(gx_device *dev):
  4380.      *
  4381.      *    Close the ilbm driver.
  4382.      */
  4383.  
  4384. private int
  4385. amiga_close_ilbm(gx_device *dev)
  4386. {
  4387.     if(xdev -> bitplane)
  4388.     {
  4389.         FreeVec(xdev -> bitplane);
  4390.  
  4391.         xdev -> bitplane = NULL;
  4392.     }
  4393.  
  4394.     if(xdev -> bitmap)
  4395.     {
  4396.         FreeVec(xdev -> bitmap);
  4397.  
  4398.         xdev -> bitmap = NULL;
  4399.     }
  4400.  
  4401.     if(xdev -> rport)
  4402.     {
  4403.         FreeVec(xdev -> rport);
  4404.  
  4405.         xdev -> rport = NULL;
  4406.     }
  4407.  
  4408.     return(0);
  4409. }
  4410.  
  4411. private int
  4412. amiga_get_params(gx_device *dev,gs_param_list *plist)
  4413. {
  4414.     int code = gx_default_get_params(dev,plist);
  4415.     gs_param_string dms;
  4416.     gs_param_string ofs;
  4417.  
  4418.     dms.data = (const byte *)xdev->display_mode,
  4419.       dms.size = strlen(xdev->display_mode),
  4420.       dms.persistent = false;
  4421.  
  4422.     ofs.data = (const byte *)xdev->file_name,
  4423.       ofs.size = strlen(xdev->file_name),
  4424.       ofs.persistent = false;
  4425.  
  4426.     /* Transmit the values. */
  4427.  
  4428.     if (code < 0 
  4429.         || (code = param_write_string(plist, "DisplayMode", &dms)) < 0
  4430.         || (code = param_write_string(plist, "OutputFile", &ofs)) < 0
  4431.        )
  4432.         return code;
  4433.  
  4434.     return 0;
  4435. }
  4436.  
  4437. private int
  4438. amiga_put_params(gx_device *dev,gs_param_list *plist)
  4439. {
  4440.     int ecode = 0;
  4441.     int code;
  4442.     const char _ds *param_name;
  4443.     gs_param_string dms;
  4444.     gs_param_string ofs;
  4445.     gs_param_float_array hwra;
  4446.     gs_param_int_array hwsa;
  4447.     
  4448.     switch ( code = param_read_string(plist, (param_name = "DisplayMode"), &dms) )
  4449.     {
  4450.     case 0:
  4451.         if ( dms.size >= (DISPLAYNAMELEN + 1) )    /* see displayinfo.h */
  4452.             ecode = gs_note_error(gs_error_limitcheck);
  4453.         else if (dms.size >= 11 && '0' == dms.data[0]    /* correct hex val? */
  4454.                 && ('x' == dms.data[1] || 'X' == dms.data[1]))
  4455.             ecode = gs_note_error(gs_error_limitcheck);
  4456.         else
  4457.             break;
  4458.         goto mide;
  4459.     default:
  4460.         ecode = code;
  4461. mide:        param_signal_error(plist, param_name, ecode);
  4462.     case 1:
  4463.         dms.data = 0;
  4464.         break;
  4465.     }
  4466.  
  4467.     switch ( code = param_read_string(plist, (param_name = "OutputFile"), &ofs) )
  4468.     {
  4469.     case 0:
  4470.         if ( ofs.size >= 256 )
  4471.           ecode = gs_note_error(gs_error_limitcheck);
  4472.         else
  4473.           break;
  4474.         goto ofe;
  4475.     default:
  4476.         ecode = code;
  4477. ofe:        param_signal_error(plist, param_name, ecode);
  4478.     case 1:
  4479.         ofs.data = 0;
  4480.         break;
  4481.     }
  4482.  
  4483.     /* Because the resolution is set after the device has been opened we need
  4484.      * to detect wether user has set -g and/or -r at the command line in 
  4485.      * order to prevent wrong computing of HWSize/MediaSize from HWResolution.
  4486.      * We therefore double the code from gsdparam.c and set global variables
  4487.      * accordingly.
  4488.      * The following code between [BEGIN] and [END ] should always double the 
  4489.      * one in gsdparam.c except those two lines marked with [ADDED].
  4490.      */
  4491.  
  4492. /* [BEGIN]: doubled code from gsdparam.c */     
  4493. #define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
  4494.   switch ( code = pread(plist, (param_name = pname), &(pa)) )\
  4495.   {\
  4496.   case 0:\
  4497.     if ( (pa).size != psize )\
  4498.       ecode = gs_note_error(gs_error_rangecheck);\
  4499.     else { 
  4500. /* The body of the processing code goes here. */
  4501. /* If it succeeds, it should do a 'break'; */
  4502. /* if it fails, it should set ecode and fall through. */
  4503. #define END_ARRAY_PARAM(pa, e)\
  4504.     }\
  4505.     goto e;\
  4506.   default:\
  4507.     ecode = code;\
  4508. e:    param_signal_error(plist, param_name, ecode);\
  4509.   case 1:\
  4510.     (pa).data = 0;        /* mark as not filled */\
  4511.   }
  4512.  
  4513.     /*
  4514.      * The HWResolution, HWSize, and MediaSize parameters interact in
  4515.      * the following way:
  4516.      *    1. Setting HWResolution recomputes HWSize from MediaSize.
  4517.      *    2. Setting HWSize recomputes MediaSize from HWResolution.
  4518.      *    3. Setting MediaSize recomputes HWSize from HWResolution.
  4519.      * If more than one parameter is being set, we apply these rules
  4520.      * in the order 1, 2, 3.  This does the right thing in the most
  4521.      * common case of setting more than one parameter, namely,
  4522.      * setting both HWResolution and HWSize.
  4523.      */
  4524.  
  4525.     BEGIN_ARRAY_PARAM(param_read_float_array, "HWResolution", hwra, 2, hwre)
  4526.         if ( hwra.data[0] <= 0 || hwra.data[1] <= 0 )
  4527.           ecode = gs_note_error(gs_error_rangecheck);
  4528.         else
  4529.         {
  4530.             ResolutionSwitch = TRUE;    /* [ADDED]: user has set -r */
  4531.           break;
  4532.         }
  4533.     END_ARRAY_PARAM(hwra, hwre)
  4534.  
  4535.     BEGIN_ARRAY_PARAM(param_read_int_array, "HWSize", hwsa, 2, hwsa)
  4536.         /* We need a special check to handle the nullpage device, */
  4537.         /* whose size is legitimately [0 0]. */
  4538.         if ( (hwsa.data[0] <= 0 && hwsa.data[0] != dev->width) ||
  4539.              (hwsa.data[1] <= 0 && hwsa.data[1] != dev->height)
  4540.            )
  4541.           ecode = gs_note_error(gs_error_rangecheck);
  4542. #define max_coord (max_fixed / fixed_1)
  4543. #if max_coord < max_int
  4544.         else if ( hwsa.data[0] > max_coord || hwsa.data[1] > max_coord )
  4545.           ecode = gs_note_error(gs_error_limitcheck);
  4546. #endif
  4547. #undef max_coord
  4548.         else
  4549.         {
  4550.             GeometrySwitch = TRUE;        /* [ADDED]: user has set -g */
  4551.           break;
  4552.         }
  4553.     END_ARRAY_PARAM(hwsa, hwse)
  4554. /* [END]: doubled code from gsdparam.c */     
  4555.  
  4556.     if (ecode < 0)
  4557.         return (ecode);
  4558.     code = gx_default_put_params(dev,plist);
  4559.     if (code < 0)
  4560.         return (code);
  4561.  
  4562.     if ( dms.data != 0 )
  4563.       {    if ( dev->is_open )
  4564.           gs_closedevice(dev);
  4565.         memcpy(xdev->display_mode, dms.data, dms.size);
  4566.         xdev->display_mode[dms.size] = 0;
  4567.       }
  4568.  
  4569.     if ( ofs.data != 0 )
  4570.       {
  4571.         memcpy(xdev->file_name, ofs.data, ofs.size);
  4572.         xdev->file_name[ofs.size] = 0;
  4573.       }
  4574.     
  4575.     if (code < 0)
  4576.         return (code);    
  4577.     return (0);    
  4578. }
  4579.  
  4580.     /* amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4581.      *
  4582.      *    Turn an RGB colour into a pen index.
  4583.      */
  4584.  
  4585. private gx_color_index
  4586. amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4587. {
  4588.     LONG max = xdev -> cube_size - 1,r,g,b;
  4589.  
  4590.     r = (max * red)   / gx_max_color_value;
  4591.     g = (max * green) / gx_max_color_value;
  4592.     b = (max * blue)  / gx_max_color_value;
  4593.  
  4594.     return((r * xdev -> cube_size + g) * xdev -> cube_size + b);
  4595. }
  4596.  
  4597.     /* amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4598.      *
  4599.      *    Turn a pen index into RGB colour values.
  4600.      */
  4601.  
  4602. private int
  4603. amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4604. {
  4605.     LONG i,value,max = xdev -> cube_size - 1;
  4606.  
  4607.     for(i = 2 ; i >= 0 ; i--)
  4608.     {
  4609.         value = color % xdev -> cube_size;
  4610.  
  4611.         rgb[i] = (gx_max_color_value * value) / max;
  4612.  
  4613.         color /= xdev -> cube_size;
  4614.     }
  4615.  
  4616.     return(0);
  4617. }
  4618.  
  4619.     /* amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4620.      *
  4621.      *    Turn an RGB colour into a pen index; this routine takes remapped
  4622.      *    pens into account.
  4623.      */
  4624.  
  4625. private gx_color_index
  4626. amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4627. {
  4628.     LONG max = xdev -> cube_size - 1,r,g,b;
  4629.  
  4630.     r = (max * red)   / gx_max_color_value;
  4631.     g = (max * green) / gx_max_color_value;
  4632.     b = (max * blue)  / gx_max_color_value;
  4633.  
  4634.     return(xdev -> pens[(r * xdev -> cube_size + g) * xdev -> cube_size + b]);
  4635. }
  4636.  
  4637.     /* amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4638.      *
  4639.      *    Turn a pen index into RGB colour values; this routine takes remapped
  4640.      *    pens into account.
  4641.      */
  4642.  
  4643. private int
  4644. amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4645. {
  4646.     LONG i,value,max = xdev -> cube_size - 1;
  4647.  
  4648.         /* Find the matching pen... */
  4649.  
  4650.     for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  4651.     {
  4652.         if(xdev -> pens[i] == color)
  4653.         {
  4654.             color = i;
  4655.  
  4656.             break;
  4657.         }
  4658.     }
  4659.  
  4660.     for(i = 2 ; i >= 0 ; i--)
  4661.     {
  4662.         value = color % xdev -> cube_size;
  4663.  
  4664.         rgb[i] = (gx_max_color_value * value) / max;
  4665.  
  4666.         color /= xdev -> cube_size;
  4667.     }
  4668.  
  4669.     return(0);
  4670. }
  4671.  
  4672.     /* amiga_copy_color8():
  4673.      *
  4674.      *    Copy a color image, the source is guaranteed to consist of
  4675.      *    one byte per colour.
  4676.      */
  4677.  
  4678. private int
  4679. amiga_copy_color8(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4680. {
  4681.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  4682.  
  4683.     base += sourcex;
  4684.  
  4685.     if(w > xdev -> width)
  4686.         w = xdev -> width;
  4687.  
  4688.     do
  4689.     {
  4690.         CopyMem((UBYTE *)base,xdev -> temp_array,w);
  4691.  
  4692.         WritePixelLine8(xdev -> rport,x,y++,w,xdev -> temp_array,xdev -> temp_rport);
  4693.  
  4694.         base += raster;
  4695.     }
  4696.     while(--h);
  4697.  
  4698.     return(0);
  4699. }
  4700.  
  4701.     /* amiga_copy_mono_raw_color():
  4702.      *
  4703.      *    Copy a monochrome image to a bitmap.
  4704.      */
  4705.  
  4706. private int
  4707. amiga_copy_mono_raw_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  4708. {
  4709.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  4710.  
  4711.     if(zero != gx_no_color_index && one != gx_no_color_index)
  4712.     {
  4713.         PLANEPTR line[12];
  4714.         LONG i,j,k,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4715.  
  4716.         for(i = 0 ; i < depth ; i++)
  4717.             line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  4718.  
  4719.         w += sourcex;
  4720.  
  4721.         if(zero == gx_no_color_index)
  4722.         {
  4723.             do
  4724.             {
  4725.                 for(i = sourcex, j = x ; i < w ; i++, j++)
  4726.                 {
  4727.                     if(base[i >> 3] & shift[i & 7])
  4728.                     {
  4729.                         for(k = 0 ; k < depth ; k++)
  4730.                         {
  4731.                             if(one & (1 << k))
  4732.                                 line[k][j >> 3] |= shift[j & 7];
  4733.                             else
  4734.                                 line[k][j >> 3] &= masks[j & 7];
  4735.                         }
  4736.                     }
  4737.                 }
  4738.  
  4739.                 base += raster;
  4740.  
  4741.                 for(k = 0 ; k < depth ; k++)
  4742.                     line[k] += modulo;
  4743.             }
  4744.             while(--h);
  4745.         }
  4746.         else
  4747.         {
  4748.             if(one == gx_no_color_index)
  4749.             {
  4750.                 do
  4751.                 {
  4752.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  4753.                     {
  4754.                         if(base[i >> 3] & shift[i & 7])
  4755.                         {
  4756.                             for(k = 0 ; k < depth ; k++)
  4757.                             {
  4758.                                 if(zero & (1 << k))
  4759.                                     line[k][j >> 3] |= shift[j & 7];
  4760.                                 else
  4761.                                     line[k][j >> 3] &= masks[j & 7];
  4762.                             }
  4763.                         }
  4764.                     }
  4765.  
  4766.                     base += raster;
  4767.  
  4768.                     for(k = 0 ; k < depth ; k++)
  4769.                         line[k] += modulo;
  4770.                 }
  4771.                 while(--h);
  4772.             }
  4773.             else
  4774.             {
  4775.                 do
  4776.                 {
  4777.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  4778.                     {
  4779.                         if(base[i >> 3] & shift[i & 7])
  4780.                         {
  4781.                             for(k = 0 ; k < depth ; k++)
  4782.                             {
  4783.                                 if(one & (1 << k))
  4784.                                     line[k][j >> 3] |= shift[j & 7];
  4785.                                 else
  4786.                                     line[k][j >> 3] &= masks[j & 7];
  4787.                             }
  4788.                         }
  4789.                         else
  4790.                         {
  4791.                             for(k = 0 ; k < depth ; k++)
  4792.                             {
  4793.                                 if(zero & (1 << k))
  4794.                                     line[k][j >> 3] |= shift[j & 7];
  4795.                                 else
  4796.                                     line[k][j >> 3] &= masks[j & 7];
  4797.                             }
  4798.                         }
  4799.                     }
  4800.  
  4801.                     base += raster;
  4802.  
  4803.                     for(k = 0 ; k < depth ; k++)
  4804.                         line[k] += modulo;
  4805.                 }
  4806.                 while(--h);
  4807.             }
  4808.         }
  4809.     }
  4810.  
  4811.     return(0);
  4812. }
  4813.  
  4814.     /* amiga_copy_color_raw_color16():
  4815.      *
  4816.      *    Copy a color image, the source data is guaranteed to consist
  4817.      *    of one word per colour.
  4818.      */
  4819.  
  4820. private int
  4821. amiga_copy_color_raw_color16(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4822. {
  4823.     PLANEPTR line[12];
  4824.     LONG i,j,k;
  4825.     LONG modulo = xdev->rport->BitMap->BytesPerRow;
  4826.     LONG depth = xdev->rport->BitMap->Depth;
  4827.     UWORD *wordbase = (UWORD *)base;
  4828.  
  4829.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  4830.  
  4831.     for(i = 0 ; i < depth ; i++)
  4832.         line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  4833.  
  4834.         w += sourcex;
  4835.  
  4836.     raster /= 2;
  4837.  
  4838.     do
  4839.     {
  4840.         for(i = sourcex, j = x ; i < w ; i++, j++)
  4841.         {
  4842.             for(k = 0 ; k < depth ; k++)
  4843.             {
  4844.                 if(wordbase[i] & (1 << k))
  4845.                     line[k][j >> 3] |= shift[j & 7];
  4846.                 else
  4847.                     line[k][j >> 3] &= masks[j & 7];
  4848.             }
  4849.         }
  4850.  
  4851.         wordbase += raster;
  4852.  
  4853.         for(k = 0 ; k < depth ; k++)
  4854.             line[k] += modulo;
  4855.     }
  4856.     while(--h);
  4857.  
  4858.     return(0);
  4859. }
  4860.  
  4861.     /* amiga_fill_rectangle_raw_color():
  4862.      *
  4863.      *    Fill a rectangular area in a bitmap.
  4864.      */
  4865.  
  4866. private int
  4867. amiga_fill_rectangle_raw_color(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  4868. {
  4869.     fit_fill(dev, x, y, w, h);
  4870.  
  4871.     if(color != gx_no_color_index)
  4872.     {
  4873.         PLANEPTR line[12];
  4874.         LONG i,j,right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4875.  
  4876.         for(i = 0 ; i < depth ; i++)
  4877.             line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo + (x >> 3);
  4878.  
  4879.         right    = x + w;
  4880.         mid    = (right >> 3) - (x >> 3);
  4881.  
  4882.         x    &= 7;
  4883.         right    &= 7;
  4884.  
  4885.         if(mid)
  4886.         {
  4887.             UBYTE *ptr;
  4888.  
  4889.             do
  4890.             {
  4891.                 for(j = 0 ; j < depth ; j++)
  4892.                 {
  4893.                     ptr = line[j];
  4894.  
  4895.                     i = mid;
  4896.  
  4897.                     if(color & (1 << j))
  4898.                     {
  4899.                         *ptr++ |= 0xFF >> x;
  4900.  
  4901.                         while(--i > 0)
  4902.                             *ptr++ = 0xFF;
  4903.  
  4904.                         *ptr |= ~(0xFF >> right);
  4905.                     }
  4906.                     else
  4907.                     {
  4908.                         *ptr++ &= ~(0xFF >> x);
  4909.  
  4910.                         while(--i > 0)
  4911.                             *ptr++ = 0x00;
  4912.  
  4913.                         *ptr &= 0xFF >> right;
  4914.                     }
  4915.  
  4916.                     line[j] += modulo;
  4917.                 }
  4918.             }
  4919.             while(--h);
  4920.         }
  4921.         else
  4922.         {
  4923.             UBYTE    one_mask    = (0xFF >> x) & ~(0xFF >> right),
  4924.                 zero_mask    = ~(0xFF >> x) | (0xFF >> right);
  4925.  
  4926.             do
  4927.             {
  4928.                 for(j = 0 ; j < depth ; j++)
  4929.                 {
  4930.                     if(color & (1 << j))
  4931.                         *line[j] |= one_mask;
  4932.                     else
  4933.                         *line[j] &= zero_mask;
  4934.  
  4935.                     line[j] += modulo;
  4936.                 }
  4937.             }
  4938.             while(--h);
  4939.         }
  4940.     }
  4941.  
  4942.     return(0);
  4943. }
  4944.  
  4945.     /* amiga_draw_line_raw_color():
  4946.      *
  4947.      *    Draw a hair line, your basic DDA algorithm;
  4948.      *    keep your fingers crossed.
  4949.      */
  4950.  
  4951. private int
  4952. amiga_draw_line_raw_color(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  4953. {
  4954.     if(color != gx_no_color_index && (x != x1 || y != y1))
  4955.     {
  4956.         LONG xstep,ystep,dx,dy,diff,modulo;
  4957.         UBYTE *line,*plane,pen;
  4958.         LONG last,i,orig_x = x,orig_y = y;
  4959.  
  4960.         modulo = xdev -> rport -> BitMap -> BytesPerRow;
  4961.  
  4962.         for(i = 0 ; i < xdev -> rport -> BitMap -> Depth ; i++)
  4963.         {
  4964.             plane    = xdev -> rport -> BitMap -> Planes[i];
  4965.             line    = &plane[y1 * modulo];
  4966.             last    = y1;
  4967.             pen    = line[x1 >> 3] & (x1 & 7);
  4968.             x    = orig_x;
  4969.             y    = orig_y;
  4970.  
  4971.             dx = x1 - x;
  4972.             dy = y1 - y;
  4973.  
  4974.             if(dx < 0)
  4975.             {
  4976.                 dx = -dx;
  4977.                 dy = -dy;
  4978.  
  4979.                 x = x1;
  4980.                 y = y1;
  4981.             }
  4982.  
  4983.             if(y != last)
  4984.                 line = &plane[(last = y) * modulo];
  4985.  
  4986.             if(color & (1 << i))
  4987.             {
  4988.                 line[x >> 3] |= shift[x & 7];
  4989.  
  4990.                 xstep = ystep = 0;
  4991.  
  4992.                 if(dy < 0)
  4993.                 {
  4994.                     if(dx > -dy)
  4995.                     {
  4996.                         diff = -dx / 2;
  4997.  
  4998.                         do
  4999.                         {
  5000.                             xstep++;
  5001.  
  5002.                             if(diff > 0)
  5003.                             {
  5004.                                 ystep--;
  5005.  
  5006.                                 diff = diff - dy - dx;
  5007.                             }
  5008.                             else
  5009.                                 diff -= dy;
  5010.  
  5011.                             {
  5012.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5013.  
  5014.                                 if(y1 != last)
  5015.                                     line = &plane[(last = y1) * modulo];
  5016.  
  5017.                                 line[x1 >> 3] |= shift[x1 & 7];
  5018.                             }
  5019.                         }
  5020.                         while(xstep < dx);
  5021.                     }
  5022.                     else
  5023.                     {
  5024.                         if(dx == -dy)
  5025.                             diff = 0;
  5026.                         else
  5027.                             diff = -dy / 2;
  5028.  
  5029.                         do
  5030.                         {
  5031.                             ystep--;
  5032.  
  5033.                             if(diff > 0)
  5034.                                 diff -= dx;
  5035.                             else
  5036.                             {
  5037.                                 xstep++;
  5038.  
  5039.                                 diff = diff - dy - dx;
  5040.                             }
  5041.  
  5042.                             {
  5043.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5044.  
  5045.                                 if(y1 != last)
  5046.                                     line = &plane[(last = y1) * modulo];
  5047.  
  5048.                                 line[x1 >> 3] |= shift[x1 & 7];
  5049.                             }
  5050.                         }
  5051.                         while(ystep > dy);
  5052.                     }
  5053.                 }
  5054.                 else
  5055.                 {
  5056.                     if(dx > dy)
  5057.                     {
  5058.                         diff = -dx / 2;
  5059.  
  5060.                         do
  5061.                         {
  5062.                             xstep++;
  5063.  
  5064.                             if(diff > 0)
  5065.                             {
  5066.                                 ystep++;
  5067.  
  5068.                                 diff = diff + dy - dx;
  5069.                             }
  5070.                             else
  5071.                                 diff += dy;
  5072.  
  5073.                             {
  5074.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5075.  
  5076.                                 if(y1 != last)
  5077.                                     line = &plane[(last = y1) * modulo];
  5078.  
  5079.                                 line[x1 >> 3] |= shift[x1 & 7];
  5080.                             }
  5081.                         }
  5082.                         while(xstep < dx);
  5083.                     }
  5084.                     else
  5085.                     {
  5086.                         if(dx == dy)
  5087.                             diff = 0;
  5088.                         else
  5089.                             diff = dy / 2;
  5090.  
  5091.                         do
  5092.                         {
  5093.                             ystep++;
  5094.  
  5095.                             if(diff > 0)
  5096.                                 diff -= dx;
  5097.                             else
  5098.                             {
  5099.                                 xstep++;
  5100.  
  5101.                                 diff = diff + dy - dx;
  5102.                             }
  5103.  
  5104.                             {
  5105.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5106.  
  5107.                                 if(y1 != last)
  5108.                                     line = &plane[(last = y1) * modulo];
  5109.  
  5110.                                 line[x1 >> 3] |= shift[x1 & 7];
  5111.                             }
  5112.                         }
  5113.                         while(ystep < dy);
  5114.                     }
  5115.                 }
  5116.  
  5117.                 if(!pen)
  5118.                 {
  5119.                     if(y1 != last)
  5120.                         line = &plane[(last = y1) * modulo];
  5121.  
  5122.                     line[x1 >> 3] &= masks[x1 & 7];
  5123.                 }
  5124.             }
  5125.             else
  5126.             {
  5127.                 line[x >> 3] &= masks[x & 7];
  5128.  
  5129.                 xstep = ystep = 0;
  5130.  
  5131.                 if(dy < 0)
  5132.                 {
  5133.                     if(dx > -dy)
  5134.                     {
  5135.                         diff = -dx / 2;
  5136.  
  5137.                         do
  5138.                         {
  5139.                             xstep++;
  5140.  
  5141.                             if(diff > 0)
  5142.                             {
  5143.                                 ystep--;
  5144.  
  5145.                                 diff = diff - dy - dx;
  5146.                             }
  5147.                             else
  5148.                                 diff -= dy;
  5149.  
  5150.                             {
  5151.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5152.  
  5153.                                 if(y1 != last)
  5154.                                     line = &plane[(last = y1) * modulo];
  5155.  
  5156.                                 line[x1 >> 3] &= masks[x1 & 7];
  5157.                             }
  5158.                         }
  5159.                         while(xstep < dx);
  5160.                     }
  5161.                     else
  5162.                     {
  5163.                         if(dx == -dy)
  5164.                             diff = 0;
  5165.                         else
  5166.                             diff = -dy / 2;
  5167.  
  5168.                         do
  5169.                         {
  5170.                             ystep--;
  5171.  
  5172.                             if(diff > 0)
  5173.                                 diff -= dx;
  5174.                             else
  5175.                             {
  5176.                                 xstep++;
  5177.  
  5178.                                 diff = diff - dy - dx;
  5179.                             }
  5180.  
  5181.                             {
  5182.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5183.  
  5184.                                 if(y1 != last)
  5185.                                     line = &plane[(last = y1) * modulo];
  5186.  
  5187.                                 line[x1 >> 3] &= masks[x1 & 7];
  5188.                             }
  5189.                         }
  5190.                         while(ystep > dy);
  5191.                     }
  5192.                 }
  5193.                 else
  5194.                 {
  5195.                     if(dx > dy)
  5196.                     {
  5197.                         diff = -dx / 2;
  5198.  
  5199.                         do
  5200.                         {
  5201.                             xstep++;
  5202.  
  5203.                             if(diff > 0)
  5204.                             {
  5205.                                 ystep++;
  5206.  
  5207.                                 diff = diff + dy - dx;
  5208.                             }
  5209.                             else
  5210.                                 diff += dy;
  5211.  
  5212.                             {
  5213.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5214.  
  5215.                                 if(y1 != last)
  5216.                                     line = &plane[(last = y1) * modulo];
  5217.  
  5218.                                 line[x1 >> 3] &= masks[x1 & 7];
  5219.                             }
  5220.                         }
  5221.                         while(xstep < dx);
  5222.                     }
  5223.                     else
  5224.                     {
  5225.                         if(dx == dy)
  5226.                             diff = 0;
  5227.                         else
  5228.                             diff =  dy / 2;
  5229.  
  5230.                         do
  5231.                         {
  5232.                             ystep++;
  5233.  
  5234.                             if(diff > 0)
  5235.                                 diff -= dx;
  5236.                             else
  5237.                             {
  5238.                                 xstep++;
  5239.  
  5240.                                 diff = diff + dy - dx;
  5241.                             }
  5242.  
  5243.                             {
  5244.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5245.  
  5246.                                 if(y1 != last)
  5247.                                     line = &plane[(last = y1) * modulo];
  5248.  
  5249.                                 line[x1 >> 3] &= masks[x1 & 7];
  5250.                             }
  5251.                         }
  5252.                         while(ystep < dy);
  5253.                     }
  5254.                 }
  5255.  
  5256.                 if(pen)
  5257.                 {
  5258.                     if(y1 != last)
  5259.                         line = &plane[(last = y1) * modulo];
  5260.  
  5261.                     line[x1 >> 3] |= pen;
  5262.                 }
  5263.             }
  5264.         }
  5265.     }
  5266.  
  5267.     return(0);
  5268. }
  5269.